Scroll-Driven Animations in Pure CSS
Scroll effects used to mean scroll event listeners or IntersectionObserver. Scroll-driven animations connect a normal CSS animation to the scroll position, and they run off the main thread, so they stay smooth.
A reading progress bar
.progress {
position: fixed;
inset: 0 0 auto 0;
height: 4px;
background: var(--brand);
transform-origin: left;
animation: grow linear;
animation-timeline: scroll(root); /* progress = how far the page has scrolled */
}
@keyframes grow {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
Reveal elements as they enter the viewport
.reveal {
animation: fade-up linear both;
animation-timeline: view(); /* progress = element's journey through the viewport */
animation-range: entry 0% cover 30%; /* animate from entering until 30% visible */
}
@keyframes fade-up {
from { opacity: 0; transform: translateY(40px); }
to { opacity: 1; transform: none; }
}
Key concepts
scroll()- a timeline based on a scroll container's position.view()- a timeline based on an element's visibility inside its scroll container.animation-range- which part of the timeline the animation covers.- Use
lineareasing; the scroll itself provides the pacing.
Progressive enhancement
@supports (animation-timeline: view()) {
.reveal { animation: fade-up linear both; animation-timeline: view(); }
}
@media (prefers-reduced-motion: reduce) {
.reveal { animation: none; }
}
Browser support is good in Chromium-based browsers and growing elsewhere, so make sure content is fully visible without the animation.
Was this article helpful?
Comments
No comments yet. Have a question or a tip? Be the first to share it.