Scroll-driven animations
Scroll-driven animations used to be only possible with the help of JavaScript.
And while there are still use cases for intersection observers, a lot of what you can do with them can be accomplished with CSS now!
We're going to keep what we're doing here pretty tame, but if you decide to go all out, please do add the animations within a prefers-reduced-motion: no-preference
media query, as we did with the smooth scrolling.
The basics
Creating scroll-driven animations is very easy, and starts the same way that you'd create any animation:
@keyframes fade-out {
from {
opacity: 1;
}
to: {
opacity: 0;
}
}
We can then apply that to an element:
.hero {
animation: fade-out forwards;
}
The big difference is, we don't supply an animation-duration
, but instead, we use an animation-timeline
.
.hero {
animation: fade-in forwards;
animation-timeline: view();
}
There are two options for the animation-timeline
, either view()
or scroll()
.
scroll()
looks at the scrolling of the entire page, from the top to the bottom.
view()
looks only at when the element is visible in the viewport.
When using view()
, the default is for it to start the animation as soon as the element enters the page, and have the animation finished when it reaches the top of the page.
In our case, that means it's starting partially faded out!
We can improve this by changing when the animation starts. In our case, we only want it to start fading out as it leaves the page:
.hero {
animation: fade-in forwards;
animation-timeline: view();
animation-range-start: exit;
}
And it's that easy!
An important limitation
There is a lot more you can do with scroll-driven animations, but one thing to be aware of is, if you're only using CSS, there is no way to "turn off" the animation once it's run.
The animation is being driven by the scrolling, so if you have elements that you want to slide into the page as the user scrolls down, but you don't want to run the animation a second time, you'll have to resort to using a little JS to do that.