CSS Scroll-Driven Animations Tutorial (2026)
This CSS scroll-driven animations tutorial replaces IntersectionObserver boilerplate with `animation-timeline: scroll()` and `view()`: build a progress bar, reveal-on-scroll cards, and parallax — plus when to keep the observer.
Count what a "simple" reveal-on-scroll costs you in 2026-era JavaScript: an IntersectionObserver with a threshold map, a callback that toggles classes, a useEffect that disconnects on unmount, root-margin tuning, a fallback for elements already in view on load, and — if you're animating progress rather than toggling — a scroll listener firing 60–120 times a second, debounce math, and geometry reads that thrash layout. The platform fixed all of this. This CSS scroll-driven animations tutorial shows you the replacement: animation-timeline , which ties keyframes to scroll position instead of wall-clock time. Three recipes, the tuning knobs, the fallbacks — and an honest table for when the observer still wins. What you'll build A reading progress bar driven by animation-timeline: scroll() — no scroll listener Reveal-on-scroll cards using animation-timeline: view() and animation-range A pure-CSS parallax band with named view timelines The entry / cover / exit tuning model for animation-range A fallback strategy so Firefox users see content, just without the motion A decision table: when to keep IntersectionObserver (or reach for GSAP) The mental model: timelines replace clocks A regular CSS animation has a timeline measured in seconds. A scroll-driven animation has a timeline measured in *scroll position*. The keyframes don't change — only what advances them does. There are two kinds of scroll timelines: scroll() — a Scroll Progress Timeline. Tracks how far a scroller has scrolled: 0% at the top, 100% at the bottom. Use it for page-level effects like progress bars and shrinking headers. view() — a View Progress Timeline. Tracks one element's visibility as it travels through the viewport: 0% when it starts entering, 100% when it finishes exiting. Use it…