Note · CSS

Scroll-driven animations without a line of JavaScript

Published 17 July 2026 · Tested on this very site

The short answer: the CSS property animation-timeline: view()drives an animation from an element's position in the viewport, with no JavaScript. Every scroll reveal on this site, including thenamesake timeline, fits in a dozen lines of CSS.

What we used to do

For fifteen years, animating on scroll meant listening to the scrollevent (and blocking the main thread), wiring upIntersectionObserver (and juggling classes), or shipping a dedicated library. Three solutions, three costs: JavaScript to load, run, and maintain.

What we write now

Here, barely simplified, is the core of this site's system:

@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .reveal {
      animation: reveal-in linear both;
      animation-timeline: view();
      animation-range: entry 5% entry 45%;
    }
  }
}

@keyframes reveal-in {
  from { opacity: 0; transform: translateY(2.2rem); }
  to { opacity: 1; transform: none; }
}

view() turns the element's journey through the viewport into the animation's timeline. animation-range selects which slice of that journey animates: here, from the element entering until 45% of its course. The animation is bound to scrolling itself: it advances and rewinds with it, for free, off the main thread.

Why it is risk-free

The two guards do all the work. @supports reserves the technique for browsers that understand it: everyone else simply sees the content, unanimated, which is a perfect fallback. And prefers-reduced-motion respects visitors who ask for calm interfaces. No content depends on an animation to be visible: that is the rule that makes everything else acceptable.

The honest limits

  • Support is not universal yet: hence the non-negotiable @supports.
  • A scroll-bound animation rewinds when you scroll back up. Intended, but worth knowing: for "play once", you still need an IntersectionObserver.
  • Animate opacity and transform only: the compositor handles them and smoothness is guaranteed. Animating anything else has a price.

The verdict

Adopted without reservation for entrance reveals. It is the first time the "appear on scroll" pattern costs zero bytes of JavaScript, and it is exactly the kind of platform progress we were waiting for.

All notes