AI CSS Animations

VU Meter Loader

Two segmented LED columns jump between levels like a stereo VU meter. The segments are a repeating-gradient mask and the level is a stepped clip-path, so it moves in whole LEDs.

Also known as: led level meter, audio meter animation, stereo level loader.

HTML

<div class="ldr-vu-meter" role="status" aria-label="Loading">
  <span></span><span></span>
</div>

CSS

.ldr-vu-meter {
  --s: var(--ldr-size, 48px);
  --c: var(--ldr-color, #3b82f6);
  display: flex;
  gap: calc(var(--s) / 7);
  height: var(--s);
}
.ldr-vu-meter span {
  position: relative;
  width: calc(var(--s) / 2.6);
  -webkit-mask: repeating-linear-gradient(to top, #000 0 calc(var(--s) / 14), transparent 0 calc(var(--s) / 10));
  mask: repeating-linear-gradient(to top, #000 0 calc(var(--s) / 14), transparent 0 calc(var(--s) / 10));
}
.ldr-vu-meter span::before,
.ldr-vu-meter span::after {
  content: "";
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--ldr-color, #3b82f6) 16%, transparent);
}
.ldr-vu-meter span::after {
  background: linear-gradient(to top, color-mix(in srgb, var(--ldr-color, #3b82f6) 65%, transparent), var(--c) 70%);
  animation: ldr-vu-meter-level 1.6s step-end infinite;
}
.ldr-vu-meter span:nth-child(2)::after {
  animation-duration: 1.36s;
  animation-delay: -0.5s;
}
@keyframes ldr-vu-meter-level {
  0%, 100% { clip-path: inset(60% 0 0 0); }
  8%   { clip-path: inset(30% 0 0 0); }
  16%  { clip-path: inset(20% 0 0 0); }
  24%  { clip-path: inset(40% 0 0 0); }
  32%  { clip-path: inset(50% 0 0 0); }
  40%  { clip-path: inset(20% 0 0 0); }
  48%  { clip-path: inset(0% 0 0 0); }
  56%  { clip-path: inset(30% 0 0 0); }
  64%  { clip-path: inset(50% 0 0 0); }
  72%  { clip-path: inset(70% 0 0 0); }
  80%  { clip-path: inset(40% 0 0 0); }
  88%  { clip-path: inset(50% 0 0 0); }
}

@media (prefers-reduced-motion: reduce) {
  .ldr-vu-meter, .ldr-vu-meter *, .ldr-vu-meter::before, .ldr-vu-meter::after, .ldr-vu-meter *::before, .ldr-vu-meter *::after {
    animation-duration: 3s;
  }
}

Customizing this loader

  • Color: set --ldr-color on the element or a parent. Currently previewing #3b82f6.
  • Size: set --ldr-size. Every dimension in the snippet is derived from it. Currently previewing 64px.
  • Speed: change the duration on the animation shorthand. Delays on the children are relative, so they keep their rhythm.
  • Accessibility: the root carries role="status" and an aria-label so screen readers announce the wait. The reduced-motion rule at the end slows the animation for users who asked for less motion.

Similar loaders