Ping
CSSA probe travels out to a node and returns, the round trip settling into a steady rhythm.
- Tier
- CSS
- Dependencies
- None
- Duration
- 2 s, loops
- Categories
- Loaders and spinners
- Use cases
- Loading and waiting
- Industries
- SaaS and software, Cross-industry
- Style
- Minimal line · light stroke
- Set
- signal
- Tags
- loopminimaluicirclepulse
Companion assets
The same artwork, not animated. Derived from the entry’s own resting state, so it matches exactly.
Code
animation.svg
<svg xmlns="http://www.w3.org/2000/svg" aria-labelledby="signal-ping-title" class="pulsar pulsar-signal-ping" data-pulsar="signal-ping" role="img" viewBox="0 0 120 40"><title id="signal-ping-title">Ping</title><circle id="signal-ping-node-a" cx="25" cy="20" r="6" fill="none" stroke="currentColor" stroke-width="2"></circle><circle id="signal-ping-node-b" cx="95" cy="20" r="6" fill="none" stroke="currentColor" stroke-width="2"></circle><line id="signal-ping-track" x1="31" x2="89" y1="20" y2="20" fill="none" stroke="currentColor" stroke-width="2" opacity=".2"></line><line id="signal-ping-probe-out" x1="31" x2="89" y1="20" y2="20" fill="none" stroke="var(--pulsar-accent, currentColor)" stroke-linecap="round" stroke-width="2" class="signal-ping-probe signal-ping-probe-out"></line><line id="signal-ping-probe-in" x1="89" x2="31" y1="20" y2="20" fill="none" stroke="var(--pulsar-accent, currentColor)" stroke-linecap="round" stroke-width="2" class="signal-ping-probe signal-ping-probe-in"></line><circle id="signal-ping-ripple-a" cx="25" cy="20" r="6" fill="none" stroke="currentColor" stroke-width="1.5" class="signal-ping-ripple signal-ping-ripple-a"></circle><circle id="signal-ping-ripple-b" cx="95" cy="20" r="6" fill="none" stroke="var(--pulsar-accent, currentColor)" stroke-width="1.5" class="signal-ping-ripple signal-ping-ripple-b"></circle></svg>
animation.css
.pulsar-signal-ping .signal-ping-probe {
stroke-dasharray: 12 46;
stroke-dashoffset: 12;
opacity: 0;
animation-duration: 2000ms;
animation-iteration-count: infinite;
animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
.pulsar-signal-ping .signal-ping-probe-out {
animation-name: signal-ping-out;
}
.pulsar-signal-ping .signal-ping-probe-in {
animation-name: signal-ping-in;
}
.pulsar-signal-ping .signal-ping-ripple {
opacity: 0;
transform-box: fill-box;
animation-duration: 2000ms;
animation-iteration-count: infinite;
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); /* crisp ease-out */
}
.pulsar-signal-ping .signal-ping-ripple-a {
transform-origin: 25px 20px;
animation-name: signal-ping-ripple-a-anim;
}
.pulsar-signal-ping .signal-ping-ripple-b {
transform-origin: 95px 20px;
animation-name: signal-ping-ripple-b-anim;
}
@keyframes signal-ping-out {
0% {
stroke-dashoffset: 12;
opacity: 1;
}
35% {
stroke-dashoffset: -46;
opacity: 1;
}
35.01%,
100% {
stroke-dashoffset: 12;
opacity: 0;
}
}
@keyframes signal-ping-in {
0%,
49.99% {
stroke-dashoffset: 12;
opacity: 0;
}
50% {
stroke-dashoffset: 12;
opacity: 1;
}
85% {
stroke-dashoffset: -46;
opacity: 1;
}
85.01%,
100% {
stroke-dashoffset: 12;
opacity: 0;
}
}
@keyframes signal-ping-ripple-a-anim {
0%,
84.99% {
transform: scale(1);
opacity: 0;
}
85% {
transform: scale(1);
opacity: 1;
}
100% {
transform: scale(2.2);
opacity: 0;
}
}
@keyframes signal-ping-ripple-b-anim {
0%,
34.99% {
transform: scale(1);
opacity: 0;
}
35% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(2.2);
opacity: 0;
}
50.01%,
100% {
transform: scale(1);
opacity: 0;
}
}
@media (prefers-reduced-motion: reduce) {
.pulsar-signal-ping .signal-ping-probe,
.pulsar-signal-ping .signal-ping-ripple {
animation: none;
}
.pulsar-signal-ping .signal-ping-probe-out {
opacity: 1;
stroke-dashoffset: -17;
}
.pulsar-signal-ping .signal-ping-probe-in {
opacity: 0;
}
.pulsar-signal-ping .signal-ping-ripple {
opacity: 0;
transform: none;
}
}