Scroll-driven animations
Learn scroll-based animation with animation-timeline: scroll().
What is a scroll-driven animation?
A scroll-driven animation progresses with the page's scroll position, not with time. As the reader scrolls down, the animation advances; scrolling back reverses it. To enable this, you set the animation-timeline property instead of relying on animation-duration.
This means you don't need a JavaScript scroll listener. The browser binds the animation's progress to the scroll position. This approach is ideal for scroll stories, progress bars, and elements that reveal on enter.
The animation-timeline property
The animation-timeline property tells the browser which timeline drives the animation. Its default value is auto, which uses the document timeline (time-based).
Set it to the scroll() function and the animation binds to scroll position. Write this property after the animation shorthand, because the shorthand resets animation-timeline to auto. This way the timeline you chose stays in effect.
Default behavior of scroll()
When you call scroll() with no arguments, the browser applies two defaults. The source is the nearest scrollable ancestor; the axis is the block axis (vertical direction).
So one screen-height of scroll completes one full animation cycle. If you have nested scroll areas, you can pass explicit arguments like scroll(root) or scroll(block nearest).
Exercise Scroll-driven opacity animation
Write two blocks. First, an @keyframes block (any name) containing from and to keyframes. Second, a CSS block for any selector; this block must contain the animation-timeline: scroll() declaration.
Show example solution
/* scroll-driven opacity */
@keyframes fade {
from { opacity: 0; }
to { opacity: 1; }
}
.reveal {
animation: 1s linear fade;
animation-timeline: scroll();
}
Test yourself
-
Which is a defining feature of a scroll-driven animation?
- Its progress is bound to scroll position
- It only starts on hover
- It plays once when the page loads
- It is triggered manually by JavaScript
Show answer
Its progress is bound to scroll position — Correct. A scroll-driven animation's progress is bound to scroll position.
-
Write a scroll timeline with scroll()
/* scroll timeline */ .reveal { animation: 1s linear fade; animation-timeline: ____; }Show answer
/* scroll timeline */ .reveal { animation: 1s linear fade; animation-timeline: scroll(); }