In this example, we’ll implement a common feature: animating a simple progress bar to scale from left to right as the user scrolls a web page. Because we want to link our animation to the progress of the root scroller, we can use an anonymous scroll progress timeline.
First let’s define the animation itself. We want our progress bar to scale from left to right, so we’ll use a transform:
@keyframes scaleProgress { 0% { transform: scaleX(0); } 100% { transform: scaleX(1); }
}
To associate our progress bar element’s animation with the progress of scroll, we’ve used the animation-timeline property and set the scroll() function as its value.
.progress { animation-timeline: scroll();
}
The scroll()
function allows us to specify the scroll container and axis. The default value is scroll(nearest block)
, meaning that the animation will be linked to the nearest scrollable ancestor on the block axis. This is sufficient for our purposes, although we could optionally specify the root as the scroll container, since we want to explicitly link the animation to the progress of scroll of the viewport.
.progress { animation-timeline: scroll(root block);
}
Lastly, we need to add our animation to the progress bar element, with our keyframe animation as the animation-name. We need to set the animation duration to auto
, as the duration will be determined by the scroll progress. We’re also setting the easing (animation-timing-function) to linear
so that it progresses smoothly in line with scroll. If we were to use the default value (ease
), the animation would start off slowly before rapidly speeding up, then slowing down at the end — not what we want from a progress indicator!
.progress { animation-timeline: scroll(root); animation-name: scaleProgress; animation-duration: auto; animation-timing-function: linear;
}
We could condense this somewhat using the animation
shorthand property:
.progress { animation: scaleProgress auto linear; animation-timeline: scroll(root);
}
Note: animation-timeline
is not currently included in the shorthand. However, the animation
property resets animation-timeline
to auto
(the default), so we need to declare animation-timeline
after the animation
shorthand.
* { box-sizing: border-box;
} body { font-family: "Helvetica", sans-serif; line-height: 1.6; min-height: 300vh; margin: 0; font-size: clamp(1rem, 1rem + 1vw, 1.5rem);
} h1 { line-height: 1.25;
} .container { max-width: 800px; margin: 0 auto; padding: clamp(1rem, 2vw, 5rem);
} .progress { height: 1rem; background: blue; position: fixed; top: 0; left: 0; width: 100%; transform-origin: 0 50%; animation: scaleProgress auto linear; animation-timeline: scroll(root);
} @keyframes scaleProgress { 0% { transform: scaleX(0); } 100% { transform: scaleX(1); }
}
<div class="progress"></div>
<div class="container"> <h1>Anonymous scroll timeline</h1> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Commodo viverra maecenas accumsan lacus. Orci sagittis eu volutpat odio facilisis mauris. Eu nisl nunc mi ipsum faucibus vitae aliquet nec. Amet nisl purus in mollis nunc sed. Egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam. Lorem sed risus ultricies tristique nulla. Commodo sed egestas egestas fringilla phasellus faucibus. Semper eget duis at tellus at urna condimentum mattis pellentesque. Porta lorem mollis aliquam ut porttitor leo a diam. At lectus urna duis convallis convallis tellus id interdum velit. Placerat orci nulla pellentesque dignissim enim sit amet venenatis urna. Rutrum tellus pellentesque eu tincidunt tortor. Nulla facilisi cras fermentum odio eu feugiat. Aliquet risus feugiat in ante metus. Quis imperdiet massa tincidunt nunc pulvinar sapien et. Vel pharetra vel turpis nunc. </p> <p> Potenti nullam ac tortor vitae purus. Tempor orci dapibus ultrices in iaculis nunc sed augue. Adipiscing elit duis tristique sollicitudin nibh. Luctus accumsan tortor posuere ac ut consequat semper. Enim nulla aliquet porttitor lacus. Netus et malesuada fames ac. Aliquam ultrices sagittis orci a scelerisque. Fringilla phasellus faucibus scelerisque eleifend donec pretium vulputate sapien. Nibh praesent tristique magna sit amet purus gravida quis. Mi proin sed libero enim sed faucibus turpis in eu. Natoque penatibus et magnis dis parturient montes nascetur ridiculus. Pellentesque elit ullamcorper dignissim cras tincidunt lobortis. Nunc faucibus a pellentesque sit amet porttitor eget dolor. Luctus accumsan tortor posuere ac ut. Et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit. Ac odio tempor orci dapibus ultrices in iaculis nunc sed. </p> <p> Molestie ac feugiat sed lectus vestibulum mattis. Elementum curabitur vitae nunc sed velit dignissim sodales ut. Netus et malesuada fames ac turpis egestas sed tempus. Viverra nam libero justo laoreet sit amet cursus sit amet. Maecenas sed enim ut sem viverra aliquet eget. Et netus et malesuada fames ac turpis egestas maecenas pharetra. Imperdiet proin fermentum leo vel orci porta. Nunc eget lorem dolor sed viverra ipsum nunc aliquet. Facilisis mauris sit amet massa vitae. Cras semper auctor neque vitae. Adipiscing diam donec adipiscing tristique risus. Scelerisque eu ultrices vitae auctor eu. Adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus urna. Egestas quis ipsum suspendisse ultrices gravida. Semper quis lectus nulla at volutpat diam. Egestas congue quisque egestas diam in arcu. </p> <p> Est velit egestas dui id ornare arcu odio ut sem. Tortor consequat id porta nibh venenatis. Proin sagittis nisl rhoncus mattis rhoncus urna neque. Porta non pulvinar neque laoreet suspendisse interdum. Lacus vel facilisis volutpat est velit egestas dui. Facilisi morbi tempus iaculis urna id volutpat. Venenatis urna cursus eget nunc scelerisque viverra. Ultrices gravida dictum fusce ut. Eu augue ut lectus arcu. Orci dapibus ultrices in iaculis. Rhoncus mattis rhoncus urna neque viverra justo nec ultrices. Odio eu feugiat pretium nibh ipsum consequat. Accumsan in nisl nisi scelerisque eu ultrices vitae. Nunc faucibus a pellentesque sit. Ultricies integer quis auctor elit sed vulputate mi. Nulla aliquet enim tortor at auctor urna nunc id cursus. </p> <p> Integer enim neque volutpat ac tincidunt vitae semper. Condimentum lacinia quis vel eros donec ac odio tempor orci. Imperdiet dui accumsan sit amet nulla facilisi morbi tempus. Suspendisse potenti nullam ac tortor vitae. Non sodales neque sodales ut. Elementum eu facilisis sed odio. Aliquet nec ullamcorper sit amet risus nullam eget felis eget. Diam phasellus vestibulum lorem sed risus ultricies tristique. Facilisis sed odio morbi quis. Diam quis enim lobortis scelerisque fermentum dui faucibus. Ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue eget. Platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim. </p>
</div>