Using the ScrollTimeline API for scroll-linked animations
Tags: css, javascript
Published: 2024-01-03 16:59:18

**Written by [Joe Attardi](https://blog.logrocket.com/author/joeattardi/)✏️**

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](https://blog.logrocket.com/the-web-animations-api-vs-css/) 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`](https://developer.mozilla.org/en-US/docs/Web/API/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](https://blog.logrocket.com/wp-content/uploads/2023/12/scroll-progress-example.gif) 

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](https://caniuse.com/mdn-api_scrolltimeline). It's supported in Chrome and Edge, but not Firefox and Safari. 

Fortunately, there is [a polyfill that will provide `ScrollTimeline`](https://github.com/flackr/scroll-timeline) 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](https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scaleX). 

First, let’s write some CSS styles:

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

  /* Start the scale transform from the left edge */
  transform-origin: left;
}
```

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

```html
<div class="progress"></div>
```

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

```javascript
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
  })
});
```

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](https://codepen.io/thinksInCode/pen/rNPPjYo).


## 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:

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

  to {
    transform: scaleX(1);
  }
}
```

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

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

The `animation` property is applied with a [linear easing function](https://blog.logrocket.com/understanding-animation-transition-timing-functions-css/) 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](https://codepen.io/thinksInCode/pen/ZEwwZmY).

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:

```css
.container {
  width: 500px;
  height: 300px;
  overflow-y: scroll;
  scroll-timeline: --container y;
}
```

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

```css
.progress {
  animation: progress linear;
  animation-timeline: --container;
}
```

You can see the [named timeline in action in this CodePen](https://codepen.io/thinksInCode/pen/oNmrxKG).

## 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](https://blog.logrocket.com/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](https://chromewebstore.google.com/detail/scroll-driven-animations/ojihehfngalmpghicjgbfdmloiifhoce) 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](https://cdpn.io/pen/debug/rNPPjYo) (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](https://blog.logrocket.com/wp-content/uploads/2023/12/chrome-devtools-scroll-driven-animations-tab.png) 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](https://blog.logrocket.com/wp-content/uploads/2023/12/progress-bar-element.png) 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](https://blog.logrocket.com/wp-content/uploads/2023/12/visible-portion-viewport.png) As you scroll down the page, the viewport indicator changes to match: ![The visible portion of the page in the viewport has changed](https://blog.logrocket.com/wp-content/uploads/2023/12/visible-portion-viewport-changed.png) 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](https://blog.logrocket.com/wp-content/uploads/2023/12/animation-scroll-percentage.png)

## 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](https://lp.logrocket.com/blg/javascript-signup): 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](https://lp.logrocket.com/blg/javascript-signup) 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](https://blog.logrocket.com/wp-content/uploads/2020/06/reproduce-javascript-errors.gif)](https://lp.logrocket.com/blg/javascript-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](https://lp.logrocket.com/blg/javascript-signup).