Scroll Driven Animations
Undoubtedly one of the most exciting developments in CSS is that we now have the ability to scroll our way through CSS animations!
There's a lot to this, so I'll just be scratching the surface.
The animation-timeline
property is the first thing you need to understand. There are two main options you can use for its value.
animation-timeline: scroll()
animation-timeline: view()
Let's dig more into scroll()
since it's a bit more straightforward...
animation-timeline: scroll()
The scroll()
value means the scrollbar is essentially the timeline for your animation. So by default the top of the page is 0% and the bottom of the page is 100%.
Notice the bar moving across the screen at the top as you scroll? That's our first example, as it's a clear demonstration of how this works.
The actual animation keyframes are very simple:
@keyframes scaleXFull {
0% {
transform: scaleX(0);
}
100% {
transform: scaleX(1);
}
}
The animation scales our div from 0 width to full width.
Now we need to apply the animation to our element:
.scroll-indicator {
animation: scaleXFull;
animation-timeline: scroll();
transform-origin: left;
}
Notice that we don't specify a duration for the animation because that's completely redundant now. The duration is however quick we scroll! Instead we have the animation-timeline: scroll()
rule.
And that's it! Now we have a pure CSS scroll indicator.
Before moving on, let's look at the animation-range
property.
/* Longhand properties
animation-range-start: 0;
animation-range-end: 100%;
*/
animation-range: cover
Obviously, a lot of the time you won't want your animation to play out over the full length of the page, and that's where the animation-range
property comes in, allowing you to specify a portion of the overall page length where the animation should run.
So if you wanted your animation to start when you've scrolled 100px and finish when you've scrolled 500px, you would do:
animation-range: 100px 500px;
You can of course use % values too.
animation-timeline: view()
With view()
, the emergence of the element itself becomes the timeline for your animation. By default, this means your animation will be at 0% when the element starts to appear and 100% when it is scrolled out of view (like how you'd use IntersectionObserver
).
I start animating as soon as my first pixel is visible, and I don't finish until my last pixel has disappeared out of view!
(animation-range: cover
)The above demo and the ones below all use the same keyframes and code, except for the animation-range
setting.
@keyframes scaleXFull {
from {
transform: scaleX(0);
}
to {
transform: scaleX(1);
}
}
@keyframes colorChange {
from {
background-color: red;
}
to {
background-color: rebeccapurple;
}
}
.element {
animation: colorChange, scaleXFull;
animation-timeline: view();
}
They all have a default pale blue background color, and when the animation kicks in it animates from red to purple. So it will be pale blue before and after the animation takes place - this is to illustrate when the animation is happening.
I start animating as soon as my first pixel is visible, and I finish as soon as I hit the top of the screen!
(animation-range: 0 100vh
)I start animating when 200px of me is visible, and I finish when 800px of me is visible
(animation-range: 200px 800px
)The animation-range
values can get so much more complex than I've shown here.
The best way to understand it all is to use these excellent visualiser tools built by Google's Bramus.
Scroll Driven Animations
Menu