Scroll Animations
Overview
Historically, triggering an animation based on the user's scroll position (e.g., a progress bar filling up as you read an article, or images fading in as they enter the screen) required heavy JavaScript libraries like GSAP or IntersectionObserver. The native CSS animation-timeline API revolutionized this. You can now map @keyframes directly to the scrollbar natively, running entirely on the compositor thread for perfect 60fps performance without a single line of JavaScript.
Syntax
/* 1. Standard Keyframes */
@keyframes fillProgress {
from { width: 0%; }
to { width: 100%; }
}
/* 2. Map it to the Scrollbar! */
.reading-progress-bar {
position: fixed;
top: 0; left: 0;
height: 5px;
background: blue;
/* Link the animation... */
animation: fillProgress linear;
/* ...but replace the time duration with the Scroll Timeline! */
animation-timeline: scroll(root block);
}Common Pitfalls
- Legacy Browser Support. Because this is a very modern API, it will completely fail on older devices or legacy enterprise environments. You must use
@supports (animation-timeline: scroll())to provide standard CSS fallbacks if the browser doesn't understand it. - Confusing
scroll()withview(). Thescroll()function maps to the overall scrollbar of the container (great for progress bars). Theview()function maps to when a specific element physically crosses into the viewport (great for reveal animations).
Interview Questions
view() timeline drastically improve performance for 'reveal on scroll' animations?Previously, JS had to attach scroll event listeners that fired hundreds of times per second, blocking the main thread. The CSS view() timeline is calculated purely by the browser's native C++ rendering engine on the GPU, completely freeing up JavaScript.
Real-World Example
Fading an image in smoothly strictly as it enters the user's viewport.
@keyframes fade-in-up {
from { opacity: 0; transform: translateY(100px); }
to { opacity: 1; transform: translateY(0); }
}
.reveal-image {
animation: fade-in-up linear both;
/* The animation runs ONLY while the element is crossing the screen! */
animation-timeline: view();
/* Start when 10% of it is visible, finish when 50% is visible */
animation-range: entry 10% cover 50%;
}Check Your Knowledge
Test your understanding of Scroll Animations with these quick questions.