Command Palette

Search for a command to run...

Hectal
Scene
12
Take
01
Level
Intermediate
Runtime
~3 h

Scroll-Driven and Scroll-Triggered Animation

Let the scroll bar drive an animation, or let scrolling start one: scroll() and view() timelines, ranges, named timelines, the JavaScript API, IntersectionObserver, Lenis, and a calm story section for the Volt.

7 shots16 live examples5 dailies
0/7 · 0%

Most animations so far run on the clock. This phase gives you a second clock, the scroll bar: a scroll-driven animation has no duration in seconds, and its progress is a scroll position, so scrolling back plays it back and stopping freezes it.

You learn the two timelines (scroll() for a scroller, view() for one element crossing the screen), the ranges entry, contain, exit and cover, named timelines and timeline-scope, the JavaScript API, and the other kind: the scroll-triggered animation, where reaching a point starts a normal timed one. You also meet sticky storytelling and smooth-scroll libraries.

Every example has its own small scroller (height: 140px; overflow: auto). At the end the Volt page gets a reading bar, a story whose features fade in, a fallback for browsers without the feature, and a switch-off for reduced motion.

▶ Roll: 12.1

Scene 12 · the brief from Lumen

Ama, head of design at Lumen Bikes

“The page is a long list of sections. I want people to feel they are moving through the Volt's story, without a gimmick that makes anyone feel sick.”

The launch page has feedback on every press, a toast, a cart, a drawer and a filterable gallery. It lacks a story. Tomás, the founder, wants four lines that tell it while people scroll.

Mei storyboards a thin orange bar across the top that fills as you read, and four features that fade in one by one. Kofi says the browser can tie an animation to the scroll bar, with no scroll listener. Lena asks what happens in a browser that cannot, and on her cheap phone.

Ravi has one request: anything that moves with scrolling must stop when he asks for less motion, and the story must read fine with it all off. By the end of this phase the page has the bar and the reveal, a fallback for older browsers, and a switch-off that follows the Phase 7 toggle.

In this scene

You will learn

  • Drive an animation from the scroll bar with scroll() and view(), and choose its range
  • Name a timeline and share it with timeline-scope, or create one in JavaScript
  • Start a timed animation when something enters view, with IntersectionObserver
  • Build the Volt story: a reading bar, a reveal, a fallback and a reduced-motion switch-off

You write code in

In your lumen-motion project (npm run dev) and in the editor on this page

Files you touch

  • src/styles/scroll.css
  • index.html
  • src/js/main.js

Shot list · 7 shots, widths by reading time

  1. 12.1Scroll Progress TimelinesA scroll progress timeline ties an animation to how far a scroller has scrolled: 0% at the top, 100% at the end. animation-timeline: scroll() does it in one line, with no scroll listener, and the animation has no duration in seconds. 20 min 2 live
  2. 12.2View Progress Timelines and RangesA view progress timeline measures how far one element has travelled across its scroller's visible area. animation-timeline: view() makes it, and animation-range chooses the part of the journey (entry, contain, exit or cover) over which the animation plays. 21 min 3 live
  3. 12.3Named Timelines and timeline-scopeA timeline can have a name, so any element can use it. scroll-timeline-name and view-timeline-name create the name, animation-timeline: --name uses it, and timeline-scope makes a name visible outside the subtree where it was made. A misspelled name raises no error. 19 min 2 live
  4. 12.4Scroll Timelines in JavaScriptnew ScrollTimeline({ source }) and new ViewTimeline({ subject }) make the same timelines from JavaScript, and element.animate(keyframes, { timeline, rangeStart, rangeEnd }) plays an animation on them. Use it for animations created at run time, and test for support first. 20 min 2 live
  5. 12.5Scroll-Triggered AnimationA scroll-triggered animation is an ordinary timed animation that starts when scrolling reaches a point. IntersectionObserver is the tool every browser has, and CSS timeline-trigger is the newer way, still not safe to depend on. 22 min 3 live
  6. 12.6Sticky Storytelling and Smooth ScrollingScrollytelling pins a stage with position: sticky while steps scroll past it, and an observer says which step is current. Smooth-scroll libraries such as Lenis replace the browser's scrolling with their own, which is why they are controversial. 19 min 2 live
  7. 12.7Build: The Volt Scroll StorybuildGive the launch page a reading bar and a story section whose four features fade in as they arrive, both driven by the scroll bar in CSS, with an IntersectionObserver fallback for browsers without view(), and all of it off for reduced motion and the site toggle. 78 min 2 live

Dailies · 5 checked exercises

A film crew watches the day's shots every evening. Build each one yourself and press Check: the page freezes its clock and checks your motion at exact moments, its cost, and its reduced-motion version.

D01A reading bar from the scrollThe bar fills over two seconds by itself, because it runs on the clock. Make it follow the box's scroll: empty at the top, half full half way, full at the end. Keep the keyframes.BeginnerD02Fade cards in as they arriveMake each card fade in and rise 24 px while it enters the box, finishing when fully inside: a view() timeline over entry, with opacity and transform only. With reduced motion the cards must simply be visible, with no animation.IntermediateD03Share a scroller's timelineThe meter under the box should follow the box's scroll, but it is full from the start. There are two problems, and the console is silent about both. Fix them: empty at the top, half full half way, full at the end.IntermediateD04Reveal cards created by codeAdd appends a card and Remove removes the last one. Give each new card a reveal on its own ViewTimeline (from entry 0% to entry 100%), after testing that ViewTimeline exists. When a card is removed, cancel its animation. Remove with no cards must do nothing and raise no error.IntermediateD05Reveal once, and never hide for goodThe features are hidden in plain CSS (opacity: 0), so a failed script leaves them invisible, and reduced motion hides them too. Rewrite the effect as in the Volt build: hide only under html.reveal-ready, which the script adds; reveal each feature once with an IntersectionObserver (add is-visible when it is in view or above the box, then stop observing it); with reduced motion do not add reveal-ready at all.Advanced