WebCraft

@keyframes + gradient

A skeleton that does not lie about the layout

CaveatA skeleton whose blocks are not the size of the real content is worse than a spinner: the page visibly rearranges the moment data lands. Match the line heights and widths you will actually render.

FallbackWrap the sweep in prefers-reduced-motion. A looping shimmer is exactly the kind of endless movement that setting exists to stop.

CSS
.line {
  background: linear-gradient(90deg,
    #1a212d 25%, #26303f 50%, #1a212d 75%)
    0 0 / 300% 100%;
  animation: sweep 1.4s linear infinite;
}
@keyframes sweep {
  to { background-position: -300% 0; }
}

Published

Questions

<details name>

Why does background-position not move my gradient?

Percentage positions are measured against the gap between the element and the image, so a background sized at 100% has no gap and cannot move. Make the gradient larger than the box, as the 300% 100% size here does, and the percentage offset starts to travel.

Should a shimmer animate transform instead of background-position?

Animating background-position repaints the element on every frame. A gradient on a pseudo-element moved with transform can run on the compositor, which matters once dozens of placeholder lines shimmer at once. Clip it with overflow: hidden on the block.

How do I make a skeleton loader accessible to screen readers?

Set aria-busy="true" on the region that is loading and hide the placeholder blocks with aria-hidden="true", since they carry no content. Remove aria-busy when the real content lands so assistive technology reads the finished region.