滚动驱动型动画性能的案例研究

Yuriko Hirota
Yuriko Hirota

滚动条驱动的动画有哪些新变化?

滚动驱动的动画是一种根据用户滚动位置触发的动画,可为您的网站或 Web 应用增添互动性和视觉趣味。这有助于吸引用户并让您的网站更具视觉吸引力。

过去,创建滚动条驱动的动画的唯一方法是在主线程上响应滚动事件。这导致了两个主要问题:

  • 滚动操作在单独的线程中执行,因此会异步传递滚动事件。
  • 主线程动画容易出现卡顿

这使得创建与滚动同步的高性能滚动条驱动的动画变得不可能或非常困难。

我们现在推出一组新的 API 来支持滚动条驱动的动画,您可以通过 CSS 或 JavaScript 使用这些 API。该 API 会尽可能少地使用主线程资源,从而使滚动驱动的动画更易于实现,也更加流畅。以下浏览器目前支持滚动驱动的动画 API:

Browser Support

  • Chrome: 115.
  • Edge: 115.
  • Firefox: behind a flag.
  • Safari: 26.

Source

本文将新方法与经典的 JavaScript 技术进行比较,以展示使用新 API 实现的滚动驱动动画有多么轻松流畅。

滚动条驱动的动画 CSS API 与经典 JavaScript

以下示例进度条是使用类 JavaScript 技术构建的。

每次发生 scroll 事件时,文档都会做出响应,以计算用户已滚动到的 scrollHeight 百分比。

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 + "%";
})

以下演示展示了使用新版 API 和 CSS 的相同进度条。

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

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

新的 animation-timeline CSS 功能会自动将滚动范围中的位置转换为进度百分比,从而完成所有繁重的工作。

现在,我们来讨论有趣的部分。假设您在网站的两个版本上都实现了一个超重的计算,该计算会占用大部分主线程资源。

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

正如您可能预料到的那样,由于主线程资源交界处,经典 JavaScript 版本变得卡顿且缓慢。另一方面,CSS 版本完全不受繁重的 JavaScript 工作的影响,可以响应用户的滚动互动。

如以下屏幕截图所示,开发者工具中的 CPU 使用率完全不同。

主线程比较。

以下演示展示了 CyberAgent 创建的滚动驱动动画的应用。您会看到,照片会在您滚动时淡入。

新的滚动条驱动的动画 JavaScript API 与经典 JavaScript

新 API 的优势不仅限于 CSS。您还可以使用 JavaScript 创建丝滑流畅的滚动驱动动画。请看以下示例:

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,
    }),
  }
);

这样一来,您就可以仅使用 JavaScript 创建与之前的 CSS 演示中所示相同的进度条动画。底层技术与 CSS 版本相同。该 API 会尽可能少地使用主线程资源,与传统的 JavaScript 方法相比,动画效果更加流畅。

此外,此新 API 可与现有的 Web Animations API (WAAPI)CSS Animations API 搭配使用,以实现声明式滚动驱动的动画。

更多演示和资源

您可以访问此演示网站,查看滚动驱动动画的不同实现方式,并比较使用 CSS 和 JavaScript 中的这些新 API 的演示。

如果您有兴趣详细了解新的滚动驱动动画,请参阅这篇文章I/O 2023 讲座