AI CSS Animations

Wavy Circle Spinner

A wavy arc grows, shrinks and rotates, like the Material 3 Expressive indicator. The squiggle is one precomputed SVG path, and pathLength keeps the dash values in plain percentages.

Also known as: material 3 expressive loading indicator, squiggly spinner, wavy progress circle.

HTML

<svg class="ldr-wavy-ring" viewBox="0 0 48 48" role="status" aria-label="Loading">
  <path pathLength="100" d="M42 24C42.5 24.9 43.4 25.9 43.3 26.8C43.2 27.6 42 28.4 41.3 29.1C40.6 29.8 39.4 30.1 39 30.9C38.7 31.6 39.2 32.7 39.1 33.7C39.1 34.7 39.3 36.1 38.7 36.8C38.2 37.4 36.8 37.4 35.8 37.6C34.8 37.8 33.6 37.4 32.9 37.9C32.2 38.3 32 39.6 31.5 40.4C30.9 41.2 30.3 42.5 29.5 42.7C28.7 43 27.5 42.2 26.6 41.8C25.6 41.4 24.9 40.5 24 40.5C23.1 40.5 22.4 41.4 21.4 41.8C20.5 42.2 19.3 43 18.5 42.7C17.7 42.5 17.1 41.2 16.5 40.4C16 39.6 15.8 38.3 15.1 37.9C14.4 37.4 13.2 37.8 12.2 37.6C11.2 37.4 9.8 37.4 9.3 36.8C8.7 36.1 8.9 34.7 8.9 33.7C8.8 32.7 9.3 31.6 9 30.9C8.6 30.1 7.4 29.8 6.7 29.1C6 28.4 4.8 27.6 4.7 26.8C4.6 25.9 5.5 24.9 6 24C6.5 23.1 7.5 22.5 7.7 21.7C7.8 20.8 7 19.9 6.7 18.9C6.5 18 5.9 16.7 6.3 15.9C6.6 15.1 8 14.7 8.9 14.3C9.7 13.8 11 13.8 11.5 13.2C12.1 12.5 11.9 11.3 12.2 10.4C12.5 9.5 12.7 8.1 13.5 7.6C14.2 7.1 15.5 7.5 16.5 7.6C17.5 7.7 18.5 8.4 19.4 8.2C20.2 7.9 20.7 6.8 21.4 6.2C22.2 5.6 23.1 4.5 24 4.5C24.9 4.5 25.8 5.6 26.6 6.2C27.3 6.8 27.8 7.9 28.6 8.2C29.5 8.4 30.5 7.7 31.5 7.6C32.5 7.5 33.8 7.1 34.5 7.6C35.3 8.1 35.5 9.5 35.8 10.4C36.1 11.3 35.9 12.5 36.5 13.2C37 13.8 38.3 13.8 39.1 14.3C40 14.7 41.4 15.1 41.7 15.9C42.1 16.7 41.5 18 41.3 18.9C41 19.9 40.2 20.8 40.3 21.7C40.5 22.5 41.5 23.1 42 24Z"></path>
</svg>

CSS

.ldr-wavy-ring {
  --s: var(--ldr-size, 48px);
  --c: var(--ldr-color, #3b82f6);
  width: var(--s);
  height: var(--s);
  animation: ldr-wavy-ring-rotate 2.8s linear infinite;
}
.ldr-wavy-ring path {
  fill: none;
  stroke: var(--c);
  stroke-width: 3.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  animation: ldr-wavy-ring-dash 1.5s cubic-bezier(0.45, 0, 0.2, 1) infinite;
}
@keyframes ldr-wavy-ring-rotate {
  to { transform: rotate(360deg); }
}
@keyframes ldr-wavy-ring-dash {
  0%   { stroke-dasharray: 4 96;  stroke-dashoffset: 0; }
  50%  { stroke-dasharray: 62 38; stroke-dashoffset: -8; }
  100% { stroke-dasharray: 4 96;  stroke-dashoffset: -100; }
}

@media (prefers-reduced-motion: reduce) {
  .ldr-wavy-ring, .ldr-wavy-ring *, .ldr-wavy-ring::before, .ldr-wavy-ring::after, .ldr-wavy-ring *::before, .ldr-wavy-ring *::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