如何创建高性能 CSS 动画

本指南将介绍如何创建高性能 CSS 动画。

如需了解这些建议背后的 理论,请参阅为什么某些动画运行缓慢?

浏览器兼容性

本指南推荐的所有 CSS 属性都具有良好的跨浏览器支持。

transform

Browser Support

  • Chrome: 36.
  • Edge: 12.
  • Firefox: 16.
  • Safari: 9.

Source

opacity

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 2.

Source

will-change

Browser Support

  • Chrome: 36.
  • Edge: 79.
  • Firefox: 36.
  • Safari: 9.1.

Source

移动元素

如需移动元素,请使用 translaterotation 关键字值,这些值是 transform 属性的。

例如,如需将某个项滑入视图,请使用 translate

.animate {
  animation: slide-in 0.7s both;
}

@keyframes slide-in {
  0% {
    transform: translateY(-1000px);
  }
  100% {
    transform: translateY(0);
  }
}

使用 rotate 旋转元素。以下示例将元素旋转 360 度。

.animate {
  animation: rotate 0.7s ease-in-out both;
}

@keyframes rotate {
  0% {
    transform: rotate(0);
  }
  100% {
    transform: rotate(360deg);
  }
}

调整元素大小

如需调整元素大小,请使用 scale 关键字值,它是 transform 属性的值。

.animate {
  animation: scale 1.5s both;
}

@keyframes scale {
  50% {
    transform: scale(0.5);
  }
  100% {
    transform: scale(1);
  }
}

更改元素的可见性

如需显示或隐藏元素,请使用 opacity

.animate {
  animation: opacity 2.5s both;
}

@keyframes opacity {
  0% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

避免使用会触发布局或绘制的属性

在将任何 CSS 属性用于动画(transformopacity 除外)之前, 请确定该属性对 渲染流水线 的影响。 除非绝对必要,否则请避免使用任何会触发布局或绘制的属性。

强制创建图层

为什么某些动画运行缓慢?中所述, 将元素放置在新图层上可让浏览器重新绘制这些元素,而无需 重新绘制布局的其余部分。

浏览器通常可以很好地决定应将哪些项放置在 新图层上,但您可以使用 will-change 属性手动强制创建图层。 顾名思义,此属性会告知浏览器此元素将以某种方式发生更改。

在 CSS 中,您可以将 will-change 应用于任何选择器:

body > .sidebar {
  will-change: transform;
}

不过,规范 建议您仅应将其添加到始终即将发生 更改的元素。例如,这可用于用户可以滑入和滑出的边栏。如果元素不经常更改,请在可能发生更改时使用 JavaScript 应用 will-change。请确保为浏览器提供足够的时间来执行必要的优化,并在更改停止后移除该属性。

如需在不支持 will-change 的浏览器中强制创建图层,您可以设置 transform: translateZ(0)

调试运行缓慢或出现故障的动画

Chrome 开发者工具 和 Firefox DevTools 可以帮助您找出动画运行缓慢 或出现故障的原因。

检查动画是否会触发布局

使用 transform 以外的其他内容移动元素的动画可能会运行缓慢。以下示例比较了使用 transform 的动画与使用 topleft 的动画。

错误做法
.box {
  position: absolute;
  top: 10px;
  left: 10px;
  animation: move 3s ease infinite;
}

@keyframes move {
  50% {
     top: calc(90vh - 160px);
     left: calc(90vw - 200px);
  }
}
正确做法
.box {
  position: absolute;
  top: 10px;
  left: 10px;
  animation: move 3s ease infinite;
}

@keyframes move {
  50% {
     transform: translate(calc(90vw - 200px), calc(90vh - 160px));
  }
}

您可以在以下两个示例中对此进行测试,并使用 DevTools 探索性能。

Chrome DevTools

  1. 打开性能 面板。
  2. 记录运行时性能 在动画发生时。
  3. 检查摘要 标签页。

如果您在摘要 标签页中看到渲染 的非零值,则可能意味着您的动画正在使浏览器执行布局工作。

“摘要”面板显示渲染时间为 37 毫秒,绘制时间为 79 毫秒。
animation-with-top-left 示例会导致渲染工作。
“摘要”面板显示渲染和绘制的零值。
animation-with-transform 示例不会导致渲染工作。

Firefox DevTools

在 Firefox DevTools 中,瀑布图 可以帮助您了解浏览器花费时间的位置。

  1. 打开性能 面板。
  2. 在动画发生时开始记录性能。
  3. 停止记录并检查瀑布图 标签页。

如果您看到重新计算样式的条目,则意味着浏览器必须返回到 渲染瀑布图 的开头才能渲染动画。

检查是否存在丢帧

  1. 在 Chrome 开发者工具 中打开 渲染 标签页
  2. 选中 FPS 计数器 复选框。
  3. 在动画运行时观看这些值。

请注意 FPS 计数器 界面顶部的 标签。 这会显示类似 50% 1 (938 m) dropped of 1878 的值。高性能动画的百分比很高,例如 99%,这意味着丢帧很少,动画看起来很流畅。

FPS 计量器显示丢弃了 50% 的帧
animation-with-top-left 示例会导致 50% 的帧被丢弃
FPS 计量器仅显示丢弃了 1% 的帧
animation-with-transform 示例只会导致 1% 的帧被丢弃。

检查动画是否会触发绘制

与某些属性相比,浏览器绘制某些属性的开销更高。例如,任何涉及模糊(例如阴影)的内容的绘制时间都比绘制红色框长。这些差异在 CSS 中并不总是很明显,但浏览器 DevTools 可以帮助您确定需要重新绘制的区域,以及其他与绘制相关的性能问题。

Chrome DevTools

  1. 在 Chrome 开发者工具 中打开 渲染 标签页
  2. 选择绘制闪烁
  3. 在屏幕上移动指针。
以绿色突出显示的界面元素,表示该元素将被重新绘制
在此 Google 地图示例中,您可以看到正在重新绘制的元素。

如果您看到整个屏幕闪烁,或者您认为不应更改的区域突出显示,请进一步调查。

如果您需要确定特定属性是否会导致 与绘制相关的性能问题,Chrome 开发者工具中的绘制性能分析器可以帮助您。

Firefox DevTools

  1. 打开设置 ,然后为 “切换绘制闪烁”添加工具箱按钮。
  2. 在要检查的页面上,开启该按钮,然后移动鼠标或滚动鼠标,以查看突出显示的区域。

在合成阶段添加动画

在可能的情况下,将动画限制为 opacitytransform,以使动画保持在渲染路径的合成阶段。使用 DevTools 检查路径的哪个阶段受到动画的影响。

使用绘制分析器查看是否有任何绘制操作的开销特别高。如果您发现任何问题,请检查是否有其他 CSS 属性可以提供相同的外观和风格,但性能更好。

请谨慎使用 will-change 属性,仅在遇到性能问题时才使用。