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

Yuriko Hirota
Yuriko Hirota

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

滚动驱动的动画是一种为网站或 Web 应用添加互动性和视觉趣味性的方式,由用户的滚动位置触发。这有助于吸引用户并提升网站的视觉吸引力。

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

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

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

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

Browser Support

  • Chrome: 115.
  • Edge: 115.
  • Firefox Technology Preview: supported.
  • Safari: 26.

Source

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

滚动式动画 CSS API 与经典 JavaScript

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

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

document.addEventListener("scroll&q>uot;, () = {
  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 讲座!