Ripple Loader

리플 로더

Outlined rings expanding outward in overlapping waves, like ripples on water — an indeterminate loader.

Also known as: Ripple ringsRadar loader
···
html
<div class="wrap" role="status" aria-live="polite">
  <div class="rp" aria-hidden="true"><span></span><span></span><span></span><i class="dot"></i></div>
  <span class="cap">테두리 원 확장 + 스태거</span>
</div>
css
.wrap{display:flex;flex-direction:column;align-items:center;gap:18px}
.rp{position:relative;width:clamp(40px,13vmin,72px);height:clamp(40px,13vmin,72px);display:grid;place-items:center}
.rp span{position:absolute;inset:0;border-radius:50%;border:2px solid var(--accent-3);animation:rip 1.8s ease-out infinite}
.rp span:nth-child(2){animation-delay:.6s}
.rp span:nth-child(3){animation-delay:1.2s}
.rp .dot{width:22%;height:22%;border-radius:50%;background:var(--accent-3)}
@keyframes rip{0%{transform:scale(.2);opacity:1}100%{transform:scale(1.05);opacity:0}}
.cap{font-size:clamp(9px,2.4vmin,11px);color:var(--muted);letter-spacing:.02em}

A stretched-out version of the pulse loader with several rings instead of one, which fits anything that's continuously searching or checking — a "my location" map marker, a radar sweep. Like the other indeterminate loaders here, it carries no real value; once progress becomes known, switch to progress-ring.

Built by stacking 2–3 outline-only circles (border, no fill) at the same spot, each animating scale from 0 upward and opacity from 1 to 0, with animation-delay staggered so the rings expand one after another. More rings read as a denser ripple, but past three it starts to look busy instead.

A skeleton usually works better for a long wait covering the whole screen; skip it entirely under 200ms. Give the wrapper role="status" and aria-live="polite", and hide the rings with aria-hidden="true" since they're decorative. Under prefers-reduced-motion, reduce the ring count or freeze the expansion and fall back to a single static circle.