DEV Community

Cover image for Using the ScrollTimeline API for scroll-linked animations
Matt Angelosanto for LogRocket

Posted on • Originally published at blog.logrocket.com

Using the ScrollTimeline API for scroll-linked animations

Written by Joe Attardi✏️

A scroll-linked, or scroll-directed, animation is an animation that is controlled by an element's scroll position. As you scroll up and down, the animation plays backward and forward.

Animations using the Web Animations API have the concept of a timeline, which controls the playback of an animation and determines what portion of the animation will play and when.

By default, an animation uses an instance of DocumentTimeline, a timeline based on the elapsed time on the page. The timeline starts at zero and moves forward in time as the animation plays. If the animation is reversed, the timeline progresses backward.

In this article, we’ll discuss how to implement scroll-linked animations in two ways, using CSS properties and using the Web Animations API.

Introducing ScrollTimeline

To create scroll-linked animations, you can use ScrollTimeline instead of the DocumentTimeline. When the element is scrolled completely to the top, the animation progress is at 0 percent — essentially, the starting keyframe. When scrolled to the bottom, it is at 100 percent — the ending keyframe.

Instead of using elapsed time, a scroll timeline uses an element's scroll position to determine the animation progress. As you scroll down, the animation begins to play in the forward direction. If you stop scrolling, the animation stops. If you start scrolling back up, the animation plays in reverse.

To illustrate this concept, consider the animation below. The blue bar animates as the scroll position changes. When scrolling down, the bar moves to the right. When scrolling up, it moves to the left:

Example of a scroll progress bar

We can create scroll timelines with a source element whose scroll position is used to drive the animation. If you want to use the document's scroll position, you can instead use document.documentElement as the source element.

Polyfilling ScrollTimeline

As of December 2023, ScrollTimeline has decent, but not full, browser compatibility. It's supported in Chrome and Edge, but not Firefox and Safari.

Fortunately, there is a polyfill that will provide ScrollTimeline functionality for these other browsers.

Building a scroll progress indicator with the Web Animations API

Let’s build an animated progress bar that tracks the reading progress of text on the page, just like the animation above. This progress bar will remain fixed at the top of the page. To animate it from left to right, we'll apply the scaleX transformation function.

First, let’s write some CSS styles:

.progress {
  height: 5px;
  background: blue;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;

  /* Start the scale transform from the left edge */
  transform-origin: left;
}
Enter fullscreen mode Exit fullscreen mode

Then, just add a div with the progress class at the top of the page:

<div class="progress"></div>
Enter fullscreen mode Exit fullscreen mode

Finally, import the polyfill and use the Web Animations API to create the scroll-linked animation:

import 'https://flackr.github.io/scroll-timeline/dist/scroll-timeline.js';

const progress = document.querySelector('.progress');

progress.animate([
  { transform: 'scaleX(0)' },
  { transform: 'scaleX(1)' }
], {
  timeline: new ScrollTimeline({
    source: document.documentElement
  })
});
Enter fullscreen mode Exit fullscreen mode

This sets up a scroll-linked scale animation that’s attached to the document scroll position. When scrolled to the very top of the page, no progress bar is visible, as the scale transform is set to zero.

As you scroll down, the scale animation progresses linearly. This means, for example, that the transform function effectively becomes scaleX(0.5) when you are exactly halfway down the page. This creates the effect of the progress bar growing from the left side of the page (since you specified a transform-origin of left).

You can see the finished animation in this CodePen.

Creating a scroll-linked animation using CSS

So far, we’ve covered how to use the Web Animations API with a ScrollTimeline object to create a scrolling progress indicator. Alternatively, you can also create this animation with a few CSS properties.

First, as with any other CSS animation, you need to create the keyframes:

@keyframes progress {
  from {
    transform: scaleX(0);
  }

  to {
    transform: scaleX(1);
  }
}
Enter fullscreen mode Exit fullscreen mode

You can create a scroll-linked animation by specifying the animation and animation-timeline properties for the progress bar element:

.progress {
  animation: progress linear;
  animation-timeline: scroll(root block);
  /* other CSS properties from before go here */
}
Enter fullscreen mode Exit fullscreen mode

The animation property is applied with a linear easing function so that the progress bar scales linearly as you scroll down the page.

Let's unpack the animation-timeline property. The scroll function tells the browser to use a scroll timeline. It takes two arguments:

  1. root: Specifies the root element of the document. This is the element whose scroll position should be linked to the timeline — when you specify the root element, which corresponds to the <html> element, you watch the scroll position within the viewport
  2. block: Specifies which scroll axis to follow. The block axis in this case is the page's Y axis, up and down the page

The CSS version of the animation can be seen in this CodePen.

The polyfill we're using is very robust, and even adds compatibility for the CSS animation-timeline property, so this solution works in all major browsers.

Named timelines with the scroll-timeline property

This example uses the root scroll timeline, which corresponds to the root element of the document. However, you can also link animation to the scroll progress of any other element on the page. To do this, the scrolling element needs a scroll-timeline defined. This can be any unique name:

.container {
  width: 500px;
  height: 300px;
  overflow-y: scroll;
  scroll-timeline: --container y;
}
Enter fullscreen mode Exit fullscreen mode

Here, the container's scroll timeline is given the name --container, which is then referenced in the animated element's animation-timeline property:

.progress {
  animation: progress linear;
  animation-timeline: --container;
}
Enter fullscreen mode Exit fullscreen mode

You can see the named timeline in action in this CodePen.

CSS vs. the Web Animations API: Which approach should you use?

There are certainly differences between CSS animations and the Web Animations API that may make an impact on your decision. For this example, it mostly comes down to preference.

If you prefer using a more declarative syntax, you might want to stick with the CSS keyframes approach. If you prefer to define your animations in JavaScript code, the Web Animations API approach will work well for you.

It's important to note that both examples in this article have the same net effect: we create a progress bar that moves as you scroll the page. Check out the article The Web Animations API vs. CSS on the LogRocket blog for a deeper dive into the differences between CSS keyframe-based animations and the Web Animations API.

Using Chrome DevTools to debug scroll-linked animations

Now that we’ve created a new scroll-linked animation, let’s practice debugging it. Install the extension in your browser.

This extension has some issues working with code inside iframes, so if you want to try the extension with a CodePen, you will need to open it in the debug view (where it is not inside an iframe).

To open the debugger, open Chrome DevTools and go to the Elements tab. You'll see a list of sub-views: Styles, Computed, etc. There should now be another tab called Scroll-Driven Animations — you may have to click the overflow icon (>>) to see it): Chrome DevTools' scroll-driven animations tab extension The Chrome extension works on the element that has a scroll-linked animation attached. Once you select the Scroll-Driven Animations tab, you'll need to select the progress bar element in the element inspector: The progress bar element is highlighted You'll see an inspector for the animation that shows the document and the portion of it that's currently visible in the viewport (the yellow outlined area): The portion of the page that is visible in the viewport As you scroll down the page, the viewport indicator changes to match: The visible portion of the page in the viewport has changed You can also see how far along you've scrolled as a fraction displayed at the top of the inspector. As you scroll, these numbers will change. In the following screenshot, the page has been scrolled about 29 percent of the way down: The animation scroll percentage, or how far down the page we've scrolled

Summary

Scroll-linked animations can be used to create all kinds of interesting effects linked to an element's scroll position. Using the Chrome DevTools extension gives you more information about the state of the animation so that you can debug any problems that occur.

The Chrome extension also works with ViewTimeline, another type of animation timeline, which lets you tie animation progress to an element's visibility within its scroll container. The extension also works with animations created using both CSS keyframe animations and the Web Animations API.


LogRocket: Debug JavaScript errors more easily by understanding the context

Debugging code is always a tedious task. But the more you understand your errors, the easier it is to fix them.

LogRocket allows you to understand these errors in new and unique ways. Our frontend monitoring solution tracks user engagement with your JavaScript frontends to give you the ability to see exactly what the user did that led to an error.

LogRocket Signup

LogRocket records console logs, page load times, stack traces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!

Try it for free.

Top comments (0)