CSS animation-timeline Property
This property allows you to link the progress of a CSS animation to a scrollbar or the position of an element within the viewport instead of the passage of time.
| none | The animation is not associated with any progress timeline. |
| auto | The default value where the animation follows the document timeline based on time. |
| <dashed-ident> | A custom name referring to a defined scroll-timeline-name or view-timeline-name. |
| scroll() | A function that sets the timeline based on the scroll progress of a specific scroll container. |
| view() | A function that sets the timeline based on the visibility of an element within its scroll container. |
Code Examples
A basic example creating a scroll-driven progress bar that fills up as the user scrolls down the page.
<style>
.progress-bar {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 10px;
background: #00ff00;
transform-origin: 0 50%;
animation: scale-up 1s linear forwards;
animation-timeline: scroll(root);
}
@keyframes scale-up {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
body { height: 3000px; margin: 0; }
</style>
<div class="progress-bar"></div>An advanced example using the view() function to fade in and slide an element up specifically as it enters the viewport.
<style>
.reveal-box {
width: 200px;
height: 200px;
margin: 500px auto;
background: #333333;
opacity: 0;
transform: translateY(50px);
animation: reveal-anim linear forwards;
animation-timeline: view();
animation-range: entry 0% cover 30%;
}
@keyframes reveal-anim {
to {
opacity: 1;
transform: translateY(0);
}
}
</style>
<div class="reveal-box"></div>
<script>
// Detect if animation-timeline is supported and log it
if (CSS.supports("animation-timeline: scroll()")) {
console.log("Scroll-driven animations are supported in this browser.");
} else {
console.log("Using standard time-based fallbacks.");
}
</script>Pro Tip
You can create a site-wide progress bar at the top of your page by applying animation-timeline: scroll(root) to a fixed element. This avoids the need for any JavaScript to calculate page height or scroll depth.
Deep Dive
By default, animations run on a clock. You set a duration, and the browser plays it from start to finish. Using animation-timeline changes the engine driving the animation. Instead of a clock, you can use the scroll position of a container or the visibility of an element. Think of it like a movie projector where the film only moves when you manually turn the crank. If you stop scrolling, the animation pauses. If you scroll backwards, the animation plays in reverse. The scroll() function looks at the scrollbar progress, while the view() function tracks an element as it enters and leaves the visible area of its parent. This replaces the need for heavy scroll-listener scripts that often bog down the main thread.
Best Practices
Use this property to enhance the user experience with progress indicators or subtle parallax effects. Always provide a time-based animation fallback for browsers that do not support scroll-driven animations yet. Keep your animations smooth by using transform and opacity properties which are cheaper for the browser to calculate during rapid scrolling.
Common Pitfalls
The most common mistake is trying to use this on an element that does not have a scrollable ancestor. If the container is not set to overflow: scroll or auto, the timeline has no room to move and the animation will stay stuck at the start. Also, keep in mind that support is currently limited to Chromium-based browsers, so do not rely on it for critical site functionality.
Accessibility
Animations triggered by scrolling can cause issues for users with motion sensitivity or vestibular disorders. Always wrap your animation-timeline logic within a media query that checks for prefers-reduced-motion: no-preference. Do not use scroll-driven animations to display essential text that the user might miss if they scroll too quickly.
Dev Data Table: animation-timeline property
| default | auto |
| animatable | no |
| inherited | no |
| experimental | yes |
| year_intro | 2022 |
| year_standard | 0 |
| js_syntax_1 | element.style.animationTimeline = "scroll()"; |
| js_syntax_2 | element.style.setProperty("animation-timeline", "scroll()"); |
| js_note | When manipulating this in JavaScript, ensure you check for browser support as this property is part of the newer Scroll-driven Animations API. |
| browsers | { "Chrome": 115, "Edge": 115, "Firefox": 0, "Safari": 0, "Opera": 101, "Chrome Android": 115, "Safari on iOS": 0, "Samsung Internet": 23, "Opera Mobile": 77 } |