CSS scroll-timeline Property
This property is a shorthand that sets both the name and the axis of a scroll timeline, allowing you to link CSS animations to the scroll position of a container.
| none | Indicates that no scroll timeline is associated with the element. |
| <dashed-ident> | A custom name for the scroll timeline, which must start with two dashes, like --my-timeline. |
| block | The scroll progress is evaluated based on the scroll position along the block axis of the container. |
| inline | The scroll progress is evaluated based on the scroll position along the inline axis of the container. |
| y | The scroll progress is evaluated based on the vertical scroll position. |
| x | The scroll progress is evaluated based on the horizontal scroll position. |
Code Examples
A basic example creating a top-of-page reading progress bar that fills up as the user scrolls down the body.
body {
scroll-timeline: --page-scroll block;
}
#progress-bar {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 8px;
background: #ff0000;
transform-origin: 0 50%;
animation: fill-progress auto linear;
animation-timeline: --page-scroll;
}
@keyframes fill-progress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}An advanced example using a local scroll container with a JavaScript fallback check to change the box color if the feature is unsupported.
<div id="container" style="height: 300px; overflow-y: scroll; scroll-timeline: --internal-scroll block;">
<div style="height: 1000px; padding-top: 50px;">
<div id="box" style="width: 100px; height: 100px; background: #0000ff; animation: rotate-box auto linear; animation-timeline: --internal-scroll;"></div>
</div>
</div>
<script>
const box = document.getElementById("box");
// Check if scroll-timeline is supported, otherwise provide fallback
if (!CSS.supports("scroll-timeline", "--any-name block")) {
box.style.backgroundColor = "#555555";
console.log("Scroll timelines not supported in this browser.");
}
</script>
<style>
@keyframes rotate-box {
from { transform: rotate(0deg); opacity: 0.2; }
to { transform: rotate(360deg); opacity: 1; }
}
</style>Pro Tip
You can apply "scroll-timeline" to the "html" or "body" tag to create a global page-scroll timeline. This is the cleanest way to build progress indicators or parallax effects that span the entire length of a document without writing a single line of JavaScript.
Deep Dive
Think of scroll-timeline as turning a scrollbar into a playback scrubber for a video. Usually, animations run on a clock with seconds or milliseconds. With this property, you create a named reference for the scrolling action of a parent container. When a child element references this name using the "animation-timeline" property, its animation progress is mapped directly to the scroll percentage. If the user scrolls 50% down the container, the animation reaches its 50% mark. It allows for highly performant scroll-driven effects because the browser handles the synchronization on the compositor thread, avoiding the main-thread lag often seen with JavaScript scroll listeners.
Best Practices
Always use a unique "dashed-ident" for the timeline name to avoid naming collisions in large projects. For the majority of web content, the "block" axis is the preferred choice as it tracks standard vertical scrolling. Since this feature is not yet supported in all browsers, you should treat scroll-driven animations as progressive enhancement. Ensure your site is perfectly functional and looks professional even if the scroll-based animations never fire.
Common Pitfalls
The most frequent mistake is applying this property to an element that does not have scrollable overflow. If the container is set to "overflow: visible" or simply doesn't have enough content to scroll, the timeline will have no progress and the animation will stay stuck at the beginning. Also, remember that "scroll-timeline" must be defined on the container that is doing the scrolling, not the element that is being animated.
Accessibility
Scroll-driven animations can cause motion sickness or distraction for users with vestibular disorders. Always wrap your scroll-linked animation code inside a "@media (prefers-reduced-motion: no-preference)" query. This ensures that users who have requested reduced motion in their system settings are not forced to experience the scrolling effects.
Dev Data Table: scroll-timeline property
| default | none block |
| animatable | no |
| inherited | no |
| experimental | yes |
| year_intro | 2022 |
| year_standard | 0 |
| js_syntax_1 | document.body.style.scrollTimeline = "--main-timeline block"; |
| js_syntax_2 | document.body.style.setProperty("scroll-timeline", "--main-timeline block"); |
| js_note | When manipulating this via JavaScript, ensure the property is supported in the user's browser, as scroll-driven animations are still emerging in some environments. |
| browsers | { "Chrome": 115, "Edge": 115, "Firefox": 0, "Safari": 0, "Opera": 101, "Chrome Android": 115, "Safari on iOS": 0, "Samsung Internet": 23, "Opera Mobile": 77 } |