PAGES

Scroll-driven animation ran in JavaScript for a decade

The pattern was everywhere before the spec existed: Apple ran it in JavaScript, and browsers took a decade to catch up.

A phone and a laptop showing the same long page at different points in its scroll
Canvas and JavaScript set the expectation years before the platform could meet it. That is the usual order.

How JavaScript wrote the spec

Apple's product pages have been doing scroll-driven animation since at least the iPhone 5s launch in 2013. The mechanic was always the same: a scroll event listener sampled window.scrollY, calculated a progress ratio, and updated inline styles or CSS custom properties on every frame. On a good day, requestAnimationFrame kept it smooth. On a bad day — a cheap Android, a cluttered main thread — it janked, because every pixel of scroll triggered JavaScript on the thread responsible for everything else.

Two screens showing the same component at different widths, a person between them
The features arrive after the pattern, and then the pattern gets cheap.

The industry noticed what Apple was doing and replicated it. Libraries accumulated: ScrollMagic, AOS (Animate On Scroll), GSAP's ScrollTrigger. GSAP in particular, built by GreenSock and first released in 2008 as a Flash tool before pivoting to DOM animation, became the production-grade answer for anyone who needed reliable scrubbing without writing the arithmetic by hand. GSAP's ScrollTrigger documentation is not a neutral source, but the problem it describes is real, and the W3C's Scroll-driven Animations specification exists to give developers a native, declarative alternative to those scripts.

The specification itself — "Scroll-driven Animations," published as a W3C Working Draft — arrived to fill exactly that hole. It introduces two timeline types: ScrollTimeline, which maps scroll position to animation progress, and ViewTimeline, which maps an element's position within a scroll container to its own progress. Both wire directly into the Web Animations API, meaning they compose with @keyframes rather than replacing them. There is no event listener. There is no main-thread involvement in the common case. The browser drives it from the compositor, which is where scroll already happens.

The browser drives it from the compositor, which is where scroll already happens.

What shipped and when

Chrome 115, released in July 2023, shipped animation-timeline: scroll() and animation-timeline: view() as stable, behind no flag. Firefox shipped the same in Firefox 110 — March 2023 — behind a flag, and has not enabled it by default since. Safari is the holdout: as of mid-2025, scroll-driven animations in CSS remain behind a flag in Safari, which means the feature cannot be used as a progressive enhancement baseline without a JavaScript fallback for a meaningful slice of mobile traffic. The @supports rule handles this cleanly — @supports (animation-timeline: scroll()) — and the fallback can be as simple as showing the end state.

An engineer at a standing desk, laptop and a second monitor showing the same page side by side at two widths, devtools open. Shot from the side so both screens and the person are i
What a phone and a laptop show at the same scroll position is the design problem underneath the effect.

The CSS surface is compact. The scroll() function takes an axis and an optional scroller reference; view() takes an animation-range that lets you clip the active range to, say, the entry phase alone. A @keyframes block does the rest. What previously required a hundred lines of JavaScript and a library dependency is now four CSS declarations.

None of this makes the JavaScript libraries obsolete today. GSAP's ScrollTrigger does things the CSS spec does not yet reach: pinning, scrub with momentum, callbacks at specific scroll positions, and sequencing across multiple elements. Linear, whose dark product page set the template for a certain kind of dense, motion-heavy interface, used JavaScript-driven scroll effects well before CSS could have handled them. The CSS feature handles the broad middle — a headline that fades in as it enters the viewport, a progress bar that fills with scroll depth — without a build step or a third-party bundle.

The usual order of events: a browser pattern gets popular enough that someone writes a library, the library gets popular enough that someone writes a spec, and the spec eventually ships in the browsers themselves. Scroll-driven animation followed that line precisely, just slowly enough that a generation of sites had to buy what is now free.