Wave Bars

웨이브 바

Several bars rising and falling on the same rhythm, staggered into a traveling wave.

Also known as: Equalizer wave
···
html
<div class="wrap" role="status" aria-live="polite">
  <div class="wb" aria-hidden="true"><span></span><span></span><span></span><span></span><span></span></div>
  <span class="cap">scaleY 동일 주기 + 스태거</span>
</div>
css
.wrap{display:flex;flex-direction:column;align-items:center;gap:18px}
.wb{display:flex;align-items:center;gap:clamp(4px,1.4vmin,7px);height:clamp(30px,9vmin,52px)}
.wb span{width:clamp(6px,2vmin,10px);height:100%;border-radius:999px;background:var(--accent);animation:wv 1s ease-in-out infinite}
.wb span:nth-child(1){animation-delay:0s}
.wb span:nth-child(2){animation-delay:.12s}
.wb span:nth-child(3){animation-delay:.24s}
.wb span:nth-child(4){animation-delay:.36s}
.wb span:nth-child(5){animation-delay:.48s}
@keyframes wv{0%,100%{transform:scaleY(.3)}50%{transform:scaleY(1)}}
.cap{font-size:clamp(9px,2.4vmin,11px);color:var(--muted);letter-spacing:.02em}

Because bars evoke audio, this shows up a lot around playback or speech recognition, but it communicates the same "still working" as any other indeterminate loader here. If there's a countable value — recognized text length, recording duration — showing that as text alongside is more useful.

Every bar shares the same scaleY keyframe (growing from 0.3× to 1× and back), with animation-delay spaced evenly across bars so the motion appears to travel from one end to the other. All bars sharing one duration is what separates this from equalizer-loader below, where each bar runs its own duration.

Prefer a skeleton for a long wait covering most of the screen, and consider skipping it entirely under 200ms. Give the wrapper role="status" and aria-live="polite", and hide the bars with aria-hidden="true" since they're decorative. Under prefers-reduced-motion, shrink the wave's amplitude or replace it with bars at a fixed height.