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

Yuriko Hirota
Yuriko Hirota

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

滚动驱动型动画是一种可通过用户的滚动位置触发,为您的网站或 Web 应用添加互动性和视觉吸引力的方式。这是一种非常有效的方式,可以提高用户互动度并让您的网站更具视觉吸引力。

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

  • 滚动是在单独的线程上执行,因此会异步传递滚动事件。
  • 主线程动画可能会卡顿

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

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

浏览器支持

  • Chrome:115.
  • Edge:115。
  • Firefox:背后有旗帜。
  • Safari:不支持。

来源

本文将这种新方法与经典 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 工作的影响,并且可以响应用户的滚动互动。

如以下屏幕截图所示,DevTools 中的 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 的演示。

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