CSS animation-timeline: scroll() — Scroll Animations Without JavaScript
Problem
Showing a scroll progress bar at the top of the page typically requires a scroll event listener and requestAnimationFrame. It works, but it’s verbose and needs performance tuning.
Solution
CSS animation-timeline: scroll() eliminates the need for JavaScript entirely.
.progress-bar {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 4px;
background: #3b82f6;
transform-origin: left;
animation: grow-progress linear;
animation-timeline: scroll();
}
@keyframes grow-progress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
<div class="progress-bar"></div>
That’s it. animation-timeline: scroll() drives the animation based on scroll position instead of time.
For animating elements as they enter the viewport, use view():
.fade-in {
animation: fade-in linear;
animation-timeline: view();
animation-range: entry 0% cover 40%;
}
@keyframes fade-in {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
animation-range gives fine-grained control over when the animation starts and ends, using keywords like entry, exit, cover, and contain.
Key Points
animation-timeline: scroll()ties animation progress to scroll positionview()triggers animations based on element viewport visibilityanimation-rangecontrols the exact animation segment- Stick to
transformandopacityfor compositor-thread rendering at 60fps - Supported in Chrome, Edge, Safari 18+. Firefox still behind a flag