scroll()
An anonymous timeline that tracks the progress of a scroll container from top to bottom. It drives the progress bar and HUD on this page.
animation-timeline: scroll(root block);
Native CSS · Baseline 2026 · Zero scroll listeners
Every frame on this page is bound to the position of your scrollbar: no scroll events, no animation library. Scroll forward and the page plays. Scroll back and it rewinds.
A ViewTimeline drives the WebGL camera on this pinned stage. The JavaScript only reads its progress. It never listens for scroll.
Each part travels its own vector, and the labels follow them in screen space. The captions come in and out on the same timeline through animation-range.
Twelve hours fit inside a quarter of this section. Scroll back and the hands run backwards.
The KHR_materials_variants swap at fixed points along the range.
Manifesto
For twenty years, motion on the web ran on the clock. We wired up scroll listeners, throttled them, and hoped the main thread kept up. Now the browser binds the animation timeline straight to the scroll offset, and it runs off the main thread. The result is buttery, reversible and declarative. Motion that answers to the reader's thumb.
Techniques
An anonymous timeline that tracks the progress of a scroll container from top to bottom. It drives the progress bar and HUD on this page.
animation-timeline: scroll(root block);
Tracks an element as it crosses the scrollport: entry, cover, contain, exit. Each word of the manifesto has its own.
animation-timeline: view();
animation-range: entry 0% cover 40%;
Slice one timeline into chapters. The four captions over the watch share a single named timeline.
animation-range:
contain 25% contain 50%;
Lifts a named timeline out of its subtree so anything can subscribe to it. The header's scrollspy needs no JavaScript.
body { timeline-scope: --s-hero, --s-watch; }
Typed custom properties interpolate, so integers count, angles spin and colors blend, all on the timeline.
@property --n { syntax: "<integer>"; }
The same timelines from JavaScript. WebGL, canvas and audio can all follow the scrollbar.
new ViewTimeline({ subject })
Gallery · view(inline)
Your vertical scroll moves a horizontal scroller. Every card animates on its own view(inline) timeline.
Principles
Animate transform, opacity, filter and clip-path, and the scroll timeline runs on the compositor, away from the main thread.
A scroll timeline has no "play once". Every state can be scrubbed back to, so design both directions.
Wrapped in @supports (animation-timeline: view()), older browsers get a calm, static page that still works.
Under prefers-reduced-motion, the theatrics turn off and the content stays.
You are now inside the letter I
Depth from a flat page.
By the numbers
stroke-dashoffset on a view() timeline