Loaders✨ Premium

Wave Bars

Five 6 × 50 px bars in indigo (#6366f1), scaleY oscillating between .4 and 1 over a 1.2 s cycle, staggered 0.1 s left to right: the wave sweeps across all five bars in 0.4 s. Pure CSS, zero JavaScript.

CSSAudio

You'll get access to the interactive demo with a free account.

This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Loaders has 29 effects, including 4 free. Explore the category →

3 usage examples

Video call — connecting to the other party while the stream is set up — Wave Bars example 1

① Video call — connecting to the other party while the stream is set up

WhenAn audio or video call screen, between accepting the call and the first media packet: the other party's avatar and name are shown, but neither sound nor picture has arrived yet.
WhyFive vertical bars side by side are the audio-level pictogram every call interface shows next to whoever is speaking. Placed under the avatar while connecting, they do not say "please wait" the way a spinner would: they stand for the signal being waited for, in the exact spot where the level meter will animate once the stream comes in. The scaleY(.4) floor keeps the bars visible between two waves (20 px), like a level meter at rest — a loader that vanished entirely would break that reading.
SettingsDimensions and color as shipped (46 × 50 px, #6366f1; height: 50px, width: 6px, gap: 4px, 1.2 s cycle) — no override of the effect's settings. The container carries role="status" aria-live="polite" with the text "Connecting…"; .loader-wave gets aria-hidden="true".
Audio player — waiting while the uploaded file is processed — Wave Bars example 2

② Audio player — waiting while the uploaded file is processed

WhenAn upload or encoding interface: after file selection, while analysis or conversion runs server-side.
WhyThe equalizer spectrum shape is the expected symbol for audio processing. The 46 × 50 px assembly fits neatly into a compact card below a progress bar, with no ambiguity about what is happening.
SettingsDimensions as shipped (46 × 50 px); color changed to #1db954 for a green-themed player, #f59e0b for a gold theme — one CSS rule to edit.
AI voice synthesis — waiting for the output — Wave Bars example 3

③ AI voice synthesis — waiting for the output

WhenA voice or music generation interface: after clicking "Generate", while the model produces audio.
WhyThe left-to-right wave motion echoes the playback of a sound waveform — the expected visual cue on a synthesis interface. At 46 px wide, the loader sits under a text field without taking over the surface.
Settingsheight: 64px, width: 8px, gap: 6px, animation-duration: 1.8s for a slower rhythm, color #a855f7.

How it works

.loader-wave is a flex row (gap: 4px, align-items: center, height: 50px) of five empty span elements, each measuring 6 × 50 px and colored #6366f1. No element is created at runtime: the five bars are declared in the sold HTML. Measured in Chromium, the whole assembly spans 46 × 50 px (5 × 6 px bars + 4 × 4 px gaps). There is no JavaScript.

The @keyframes wave animation drives a scaleY from the vertical origin: 0%scaleY(.4) (visual height 20 px), 20%scaleY(1) (full height 50 px), back to scaleY(.4) at 40% and held through 100%. The rise and fall each take 240 ms; each bar stays at its minimum for 720 ms, or 60% of the 1.2 s cycle. Each span carries a negative delay decreasing by 0.1 s steps: −1.2 s / −1.1 s / −1.0 s / −0.9 s / −0.8 s. The height peak therefore travels bar by bar from left to right, producing a wave that sweeps across the five bars in 0.4 s, then repeats.

Measured in Chromium: at t ≈ 0, bar 1 reaches scaleY(0.986) (near full height) while bars 4 and 5 are at scaleY(0.4); at t ≈ 600 ms, bars 4 and 5 are at their maximum and bars 1 and 2 are at rest. No console errors. The animation runs continuously (animation-iteration-count: infinite) with no stop condition: the loader keeps running as long as it is in the DOM.

Accessibility

  • prefers-reduced-motion not handled — measured: under Chromium's prefers-reduced-motion: reduce emulation, all five bars keep animating (animationPlayState: running) with no change. Add @media (prefers-reduced-motion: reduce) { .loader-wave span { animation: none; transform: scaleY(.4); } } — bars stay visible at their minimum height (20 px).
  • No ARIA attributes: .loader-wave carries neither role="status", nor aria-label, nor aria-busy, nor aria-live. Screen readers receive no indication that content is loading. Add role="status" aria-label="Loading" aria-live="polite" to .loader-wave, or manage state via aria-busy="true" on the parent region.
  • The five span elements are empty. Add aria-hidden="true" to the .loader-wave container to exclude them from the accessibility tree: the text from aria-label will then be the only content announced.
  • Contrast: #6366f1 on #0a0a0f (demo background) = 5.5:1; on white = 4.5:1 — both pass the 3:1 threshold for graphical elements. On a light grey background (#e5e7eb), the ratio drops to 2.1:1: switch to #4338ca (8.2:1 on white) or place a dark background behind the loader.

Browser compatibility

Pure CSS: requires @keyframes, transform: scaleY(), negative animation-delay and display: flex with gap. Zero dependencies, zero JavaScript. The limiting factor is gap on flexbox.

Chrome 84+✓ Full
Firefox 63+✓ Full
Safari 14.1+✓ Full
Edge 84+✓ Full
Mobile iOS 14.5+✓ Full (self-running CSS animation)
Android Chrome 84+✓ Full (self-running CSS animation)

Without gap on flex (Chrome < 84, Safari < 14.1), the bars sit flush against each other: replace gap: 4px with margin-right: 4px on .loader-wave span and add .loader-wave span:last-child { margin-right: 0 }. Without CSS animations (IE 9), the five bars appear frozen at 50 px.

The code

HTML structure to paste into your page (CSS + JS available with a premium account):

index.html — structure
<div class="loader-wave">
  <span></span>
  <span></span>
  <!-- … 5 bars total —
       each span has its animation-delay in the CSS -->
</div>
🔒 Unlock the full code — from €2.99 the first month

Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Bar count (HTML — spans + CSS — nth-child animation-delay) 5 Each added bar needs a new nth-child rule with a delay decremented by 0.1 s. A 6th bar gets animation-delay: −0.7 s. Reducing to 3 bars brings the loader down to 22 × 50 px.
Zone height (CSS — .loader-wave { height: 50px }) 50 px Reference height for the bars before scaleY. The rendered minimum height is height × .4 (20 px), the maximum is this value. 32px for a button; 80px for a large audio display.
Bar width (CSS — .loader-wave span { width: 6px }) 6 px Width of each bar, independent of height. 4px for a discreet indicator; 10px for a VU-meter-style display.
Gap between bars (CSS — .loader-wave { gap: 4px }) 4 px 2px = nearly flush bars (dense equalizer look); 8px = well-spaced bars.
Color (CSS — .loader-wave span { background: #6366f1 }) #6366f1 Solid color for all five bars. For a vertical gradient, replace background with background: linear-gradient(to top, #6366f1, #a5b4fc).
Cycle duration (CSS — animation: 1.2s … on the span elements) 1.2 s Duration of one full cycle. 0.8 s = fast wave; 2 s = slow rhythm. Changing the duration does not alter relative stagger between bars — the wave stays coherent.
Stagger between bars (CSS — step between animation-delay values) 0.1 s per bar (0.4 s total across 5 bars) Delay between two consecutive bars. Wave travel time = (n − 1) × stagger. At 0.2 s, the wave takes 0.8 s to cross all 5 bars. Keep delays negative so the animation is already underway on page load.
Amplitude (CSS — @keyframes wave: scaleY(.4) min, scaleY(1) max) scaleY .4 to 1 (20 px to 50 px) Minimum and maximum height of each bar. scaleY(.2) = very thin bars at rest (10 px); scaleY(0) = bars vanish completely (they then look like vertical pulses appearing from nothing).

FAQ

They stay visible. The keyframe drops to scaleY(.4), never to scaleY(0): on a height: 50px zone, the rendered minimum height is exactly 20 px (measured in Chromium). For bars that vanish completely, replace scaleY(.4) with scaleY(0) in the three keyframe positions where it appears (0%, 40%, and 100%) — the result looks more like vertical pulses shooting up and disappearing.
Add a span to the HTML and an nth-child rule in the CSS with a delay decremented by 0.1 s. For the nth bar (starting at 1): animation-delay: −(1.2 − (n − 1) × 0.1) s. For 6 bars, the 6th gets −0.7 s; for 7 bars, the 7th gets −0.6 s. For a large number of bars, reduce the stagger (e.g. 0.05 s) so the last bar still has a negative delay.
Wave Form (fx-0517) draws a continuous SVG path animated by JavaScript (requestAnimationFrame + two superimposed sinusoids), spanning the full width of its container. Wave Bars (fx-0426) is a set of five discrete bars, pure CSS, simulating an equalizer or VU-level display. Wave Form is an oscilloscope — a smooth, continuous waveform suited to an animated background; Wave Bars is a compact loading indicator (46 × 50 px), JavaScript-free, built for a UI component.