A case study on scroll-driven animations performance

Yuriko Hirota
Yuriko Hirota

What’s new with scroll-driven animations?

Scroll-driven animations are a way to add interactivity and visual interest to your website or web application, triggered by the user's scroll position. This can be a great way to keep users engaged and make your website more visually appealing.

In the past, the only way to create scroll-driven animations was to respond to the scroll event on the main thread. This caused two major problems:

  • Scrolling is performed on a separate thread and therefore delivers scroll events asynchronously.
  • Main thread animations are subject to jank.

This makes creating performant scroll-driven animations that are in-sync with scrolling impossible or very difficult.

We are now introducing a new set of APIs to support scroll-driven animations, which you can use from CSS or JavaScript. The API tries to use as few main thread resources as possible, making scroll-driven animations far easier to implement, and also much smoother. The scroll-driven animations API is currently supported in the following browsers:

Browser Support

  • Chrome: 115.
  • Edge: 115.
  • Firefox: behind a flag.
  • Safari: not supported.

Source

This article compares the new approach with the classic JavaScript technique to show just how easy and silky-smooth scroll-driven animations can be with the new API.

The scroll-driven animations CSS API versus classic JavaScript

The following example progress bar is built using class JavaScript techniques.

The document responds each time the scroll event happens to calculate how much percentage of the scrollHeight the user has scrolled to.

document.addEventListener("scroll", () => {
  var winScroll = document.body.scrollTop || document.documentElement.scrollTop;
  var height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
  var scrolled = (winScroll / height) * 100; 
  document.getElementById("progress").style.width = scrolled + "%";
})

The following demo shows the same progress bar using the new API with CSS.

@keyframes grow-progress {
  from {
    transform: scaleX(0);
  }
  to {
    transform: scaleX(1);
  }
}

#progress {
  animation: grow-progress auto linear forwards;
  animation-timeline: scroll(block root);
}

The new animation-timeline CSS feature, automatically converts a position in a scroll range into a percentage of progress, therefore doing all the heavy-lifting.

Now here’s the interesting part—let’s say that you implemented a super-heavy calculation on both versions of the website that would eat up most of the main thread resources.

function someHeavyJS(){
  let time = 0;
  window.setInterval(function () {
    time++;
    for (var i = 0; i < 1e9; i++) {
      result = i;
    }
    console.log(time)
  }, 100);
}

As you might have expected, the classic JavaScript version becomes janky and sluggish due to the main thread resources junction. On the other hand, the CSS version is completely unaffected by the heavy JavaScript work and can respond to the user's scroll interactions.

The CPU usage is completely different in DevTools, as shown in the following screenshots.

Main thread comparison.

The following demo shows an application of scroll driven animation created by CyberAgent. You can see that the photo fades in as you scroll.

New scroll-driven animations JavaScript API versus classic JavaScript

The benefit of the new API is not only limited to CSS. You are able to create silky smooth scroll-driven animations using JavaScript as well. Take a look at the following example:

const progressbar = document.querySelector('#progress');
progressbar.style.transformOrigin = '0% 50%';
progressbar.animate(
  {
    transform: ['scaleX(0)', 'scaleX(1)'],
  },
  {
    fill: 'forwards',
    timeline: new ScrollTimeline({
      source: document.documentElement,
    }),
  }
);

This enables you to create the same progress bar animation shown in the previous CSS demo using just JavaScript. The underlying technology is the same as the CSS version. The API tries to use as few main thread resources as possible, making the animations far smoother when compared to the classic JavaScript approach.

Also, this new API works in conjunction with the existing Web Animations API (WAAPI) and CSS Animations API to enable declarative scroll-driven animations.

More demos and resources

You can check out the different implementations of scroll driven animation via this demo site, where you can compare demos using these new APIs from CSS and JavaScript.

If you are interested in learning more about the new scroll-driven animations, check out this article and the I/O 2023 talk!