CSS Scroll-Driven Animations
Link CSS animations to scroll position usinganimation-timeline: scroll()
What are Scroll-Driven Animations?
Scroll-driven animations allow you to link CSS animations to scroll position instead of time. As the user scrolls, the animation progresses - no JavaScript needed.
Two Types of Scroll Timelines
Scroll Progress Timeline
Links animation to scroll position of a scroll container. Think: progress bars, parallax effects.
animation-timeline: scroll()View Progress Timeline
Links animation to an element's visibility in the viewport. Think: reveal animations, sticky effects.
animation-timeline: view()Browser Support
Scroll-driven animations are currently supported in Chromium browsers (Chrome 115+, Edge 115+). Safari and Firefox do not yet support this feature.
Use as progressive enhancement. Non-supporting browsers will see static content or time-based fallback animations.
Scroll Progress Indicator
The classic use case: a progress bar that fills as you scroll down the page.
How It Works
1. Define a standard keyframe animation (scale from 0 to 1)
2. Set animation-timeline: scroll()
3. The animation progress now tracks scroll position
4. At top of page = 0%, at bottom = 100%
CSS Code
/* Scroll progress indicator */
.progress-bar {
position: fixed;
top: 0;
left: 0;
height: 4px;
background: linear-gradient(to right, #667eea, #764ba2);
transform-origin: left;
animation: grow-progress linear;
animation-timeline: scroll();
}
@keyframes grow-progress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}scroll() Function Syntax
The scroll() function specifies which scroll container to track.
Syntax Reference
/* scroll() function syntax */
animation-timeline: scroll(); /* Nearest scroller, block axis */
animation-timeline: scroll(root); /* Root scroller (viewport) */
animation-timeline: scroll(nearest); /* Nearest ancestor scroller */
animation-timeline: scroll(self); /* Element itself if scrollable */
/* With axis */
animation-timeline: scroll(root block); /* Vertical scroll */
animation-timeline: scroll(root inline); /* Horizontal scroll */
animation-timeline: scroll(root x); /* X axis */
animation-timeline: scroll(root y); /* Y axis */
/* Named scroll timeline */
.scroll-container {
scroll-timeline-name: --my-scroller;
scroll-timeline-axis: block;
/* Shorthand: scroll-timeline: --my-scroller block; */
}
.animated-element {
animation-timeline: --my-scroller;
}| Scroller Value | Description |
|---|---|
root | The document viewport |
nearest | Nearest scrollable ancestor (default) |
self | The element itself |
View Progress Timeline
view() tracks an element's visibility in the viewport, perfect for scroll-reveal animations.
Animation Range
The animation-range property defines when the animation starts and ends relative to the element's visibility.
| Range Name | Description |
|---|---|
cover | From first visible pixel to last (full travel) |
contain | While fully visible in viewport |
entry | While entering the viewport |
exit | While exiting the viewport |
entry-crossing | While crossing the entry edge |
exit-crossing | While crossing the exit edge |
CSS Code
/* Reveal animation when element enters viewport */
.reveal-element {
opacity: 0;
transform: translateY(50px);
animation: reveal linear both;
animation-timeline: view();
animation-range: entry 0% entry 100%;
}
@keyframes reveal {
to {
opacity: 1;
transform: translateY(0);
}
}
/* Image zoom as it scrolls through viewport */
.zoom-image {
animation: zoom linear both;
animation-timeline: view();
animation-range: contain 0% contain 100%;
}
@keyframes zoom {
from { transform: scale(0.8); }
to { transform: scale(1); }
}Parallax Scrolling
Create parallax effects by animating elements at different rates relative to scroll.
The Technique
- Create a named scroll timeline on the scroll container
- Reference that timeline from child elements
- Use different translateY distances for each layer
- Slower-moving elements appear farther away
CSS Code
/* Parallax scrolling effect */
.parallax-container {
scroll-timeline-name: --parallax;
overflow-y: scroll;
height: 100vh;
}
.parallax-slow {
animation: parallax-slow linear;
animation-timeline: --parallax;
}
.parallax-fast {
animation: parallax-fast linear;
animation-timeline: --parallax;
}
@keyframes parallax-slow {
from { transform: translateY(0); }
to { transform: translateY(-50px); }
}
@keyframes parallax-fast {
from { transform: translateY(0); }
to { transform: translateY(-150px); }
}Sticky Header Animation
A common pattern: header that shrinks and gains a background as you scroll.
Key Concept: animation-range
Use animation-range: 0 200px to complete the animation within the first 200px of scroll, then hold the final state.
The forwards fill mode keeps the animation at its end state after the range completes.
CSS Code
/* Header that shrinks on scroll */
.header {
position: sticky;
top: 0;
animation: shrink-header linear forwards;
animation-timeline: scroll();
animation-range: 0 200px;
}
@keyframes shrink-header {
from {
padding: 2rem 1rem;
background: transparent;
}
to {
padding: 0.5rem 1rem;
background: white;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
}
/* Logo shrinks with header */
.header-logo {
animation: shrink-logo linear forwards;
animation-timeline: scroll();
animation-range: 0 200px;
}
@keyframes shrink-logo {
from { height: 60px; }
to { height: 40px; }
}Polyfill for Broader Support
The scroll-timeline polyfill provides support for Firefox and Safari while native support is pending.
Using the Polyfill
<!-- Include polyfill for non-Chrome browsers -->
<script src="https://flackr.github.io/scroll-timeline/dist/scroll-timeline.js"></script>
<!-- Your CSS works the same way -->
<style>
.animated {
animation: fade-in linear;
animation-timeline: scroll();
}
</style>Progressive Enhancement Strategy
- Design for no animation (content still works)
- Add scroll-driven animations in CSS
- Optionally include polyfill for broader support
- Test in all target browsers
CSS vs JavaScript Scroll Animations
| Aspect | CSS Scroll-Driven | JavaScript (Intersection/Scroll) |
|---|---|---|
| Performance | Runs on compositor | Main thread |
| Code location | CSS only | JS + CSS |
| Complexity | Lower (declarative) | Higher (imperative) |
| Browser support | Chrome only | All browsers |
| Fine control | Limited | Full control |
When to Use CSS Scroll Animations
- Progress indicators and scroll-linked transforms
- Simple reveal animations on scroll
- Parallax effects
- Header shrink effects
When to Use JavaScript
- Complex multi-element orchestration
- Conditional animations based on data
- Animations requiring broad browser support today
- Fine-grained scroll position callbacks
Explore more CSS tools
CSS Grid Generator
Create grid layouts visually
CSS Flexbox Generator
Create flex layouts visually
CSS Gradient Generator
Create custom gradients
CSS Text Gradient
Gradient text effects
CSS Gradients Collection
275+ ready-to-use gradients
CSS Box Shadow Generator
Design multi-layer shadows
CSS Selection Generator
Style text highlight colors
CSS Scrollbar Generator
Style custom scrollbars
CSS Blend Mode Generator
Mix colors with blend modes
CSS Cursor Generator
Preview all cursor styles
CSS Loader Generator
Create loading animations
CSS Button Generator
Design buttons with hover effects
CSS Glow Generator
Create neon glow effects
Fluid Typography
Scale text across screen sizes
