A thick sine squiggle scrolls sideways and fades out at both ends, the wavy indicator style of newer Material designs. The SVG shifts by exactly one wavelength per loop, so it never jumps.
Also known as: squiggle loader, wave line animation, squiggly progress indicator.
<div class="ldr-wavy-line" role="status" aria-label="Loading"> <svg viewBox="0 0 100 20" aria-hidden="true"><path d="M0 10 Q5 -2 10 10 T20 10 T30 10 T40 10 T50 10 T60 10 T70 10 T80 10 T90 10 T100 10" /></svg> </div>
.ldr-wavy-line {
--s: var(--ldr-size, 48px);
--c: var(--ldr-color, #3b82f6);
overflow: hidden;
width: calc(var(--s) * 2);
height: calc(var(--s) * 0.6);
-webkit-mask: linear-gradient(90deg, transparent, #000 22% 78%, transparent);
mask: linear-gradient(90deg, transparent, #000 22% 78%, transparent);
}
.ldr-wavy-line svg {
display: block;
width: calc(var(--s) * 2.5);
height: calc(var(--s) * 0.5);
margin-top: calc(var(--s) * 0.05);
overflow: visible;
fill: none;
stroke: var(--c);
stroke-width: 3;
stroke-linecap: round;
animation: ldr-wavy-line-scroll 0.9s linear infinite;
}
@keyframes ldr-wavy-line-scroll {
to { transform: translateX(-20%); }
}
@media (prefers-reduced-motion: reduce) {
.ldr-wavy-line, .ldr-wavy-line *, .ldr-wavy-line::before, .ldr-wavy-line::after, .ldr-wavy-line *::before, .ldr-wavy-line *::after {
animation-duration: 3s;
}
}--ldr-color on the element or a parent.
Currently previewing #3b82f6.--ldr-size. Every dimension in the snippet is
derived from it. Currently previewing 64px.animation shorthand.
Delays on the children are relative, so they keep their rhythm.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.