Tools

Scroll Animation Builder

Animations whose progress is the scroll position, running off the main thread with no listener and no observer. Scroll the preview, change the range, and copy a block that is safe to ship today.

Limited availability

Scroll down inside this box ↓

First card
Second card
Third card
Fourth card
Fifth card

The end.

CSS

Two timelines

scroll() ties an animation to how far a scroller has scrolled, start to end. That is a reading progress bar. view() ties it to one element’s journey through the viewport, which is a reveal as a card arrives. The keyframes are ordinary keyframes. The only new idea is that time has been replaced by position, so animation-duration stops meaning anything and the range takes over.

The range is the design

animation-range: entry 0% cover 40% reads as: start when the element’s leading edge enters the viewport, and be finished by the time it has covered forty percent of the way across. A short range snaps in; a long one drifts. Most reveals that feel wrong are using the whole range, so the element is still fading when it reaches the middle of the screen.

Why the output is wrapped twice

Outside the guards the element is in its finished state, fully visible. Inside @supports (animation-timeline: view()) and prefers-reduced-motion: no-preference it gets the animation. A browser without the feature, or a reader who asked for less motion, sees the content with nothing missing. Never put the hidden starting state outside the guard. See the feature page for current support.