CSS Scroll-Driven Animations
Animations that respond to scroll position - all in pure CSS. Create parallax effects, reveal animations, and scroll progress indicators without a single line of JavaScript.
The Future of Scroll Effects
For years, scroll-triggered animations required JavaScript libraries, scroll listeners, and performance concerns. CSS Scroll-Driven Animations changes the game - animations driven by scroll position, completely declarative.
Scroll Down
This element fades in as you scroll
@keyframes fade-in {
from { opacity: 0; transform: translateY(50px); }
to { opacity: 1; transform: translateY(0); }
}
.element {
animation: fade-in linear;
animation-timeline: view();
animation-range: entry 0% cover 30%;
}
Key Concepts
- animation-timeline: Links animation to scroll instead of time
- scroll(): Animates based on scroll container position
- view(): Animates based on element visibility in viewport
- animation-range: Controls when animation starts/ends during scroll
Scroll Progress Indicator
Create reading progress bars that fill as you scroll - perfect for blog posts and articles.
The bar above fills as you scroll this page!
@keyframes grow-progress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
.progress-bar {
position: fixed;
top: 0;
left: 0;
height: 4px;
background: #2563eb;
transform-origin: 0 50%;
animation: grow-progress linear;
animation-timeline: scroll(root);
}
Reveal on Scroll
Elements animate into view as they enter the viewport - the classic "scroll reveal" effect, now in pure CSS.
@keyframes reveal {
from {
opacity: 0;
transform: translateY(100px) scale(0.8);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
.card {
animation: reveal linear;
animation-timeline: view();
animation-range: entry 0% cover 40%;
}
Browser Support
⚠️ Cutting-Edge Feature
Scroll-Driven Animations are very new!
- Chrome 115+: Fully supported ✅
- Edge 115+: Fully supported ✅
- Firefox: Behind flag 🚧
- Safari: In development 🚧
For production: Use progressive enhancement. The animations won't run in unsupported browsers, but your content will still be visible.
/* Progressive enhancement */
.element {
opacity: 1; /* Default state for unsupported browsers */
}
@supports (animation-timeline: view()) {
.element {
opacity: 0; /* Start hidden only if supported */
animation: fade-in linear;
animation-timeline: view();
}
}
Why This Matters
Scroll-Driven Animations eliminate common problems:
- ✅ Performance: Browser-optimized, runs on compositor thread
- ✅ No JavaScript: Pure CSS means no scroll listeners, no jank
- ✅ Declarative: Define what you want, browser handles how
- ✅ Accessibility: Respects prefers-reduced-motion automatically