【问题标题】:CSS keyframe animation CPU usage is high, should it be this way?CSS关键帧动画CPU占用率高,应该这样吗?
【发布时间】:2012-10-22 00:30:12
【问题描述】:

我在几个元素上使用了以下关键帧动画:

@keyframes redPulse {
    from { background-color: #bc330d; box-shadow: 0 0 9px #333; }
    50% { background-color: #e33100; box-shadow: 0 0 18px #e33100; }
    to { background-color: #bc330d; box-shadow: 0 0 9px #333; }
}
@-webkit-keyframes redPulse {
    from { background-color: #bc330d; box-shadow: 0 0 9px #333; }
    50% { background-color: #e33100; box-shadow: 0 0 18px #e33100; }
    to { background-color: #bc330d; box-shadow: 0 0 9px #333; }
}
.event_indicator {
    display: inline-block;
    background-color: red;
    width: 5px;
    margin-right: 5px;

    -webkit-animation-name: redPulse;
    -webkit-animation-duration: 1s;
    -webkit-animation-iteration-count: infinite;

    animation-name: redPulse;
    animation-duration: 1s;
    animation-iteration-count: infinite;
}

在我的计算机上,Chrome 和 Firefox 的 CPU 使用率都在 40% 左右。 是动画的当前状态(不错,但暂时不可用)还是我缺少一些神奇的属性?

您可以使用相同的动画查看以下示例: http://jsfiddle.net/Nrp6Q/

【问题讨论】:

  • 除了高 CPU,在我的情况下,它似乎还与不断增加的内存占用有关,基于 Chrome 任务管理器。
  • @KevinBullaughey,显然,每个对象都有成本:它们占用系统 RAM 和/或 GPU 中的内存,请参阅the explanation,而且动画本身是一项相对昂贵的操作!跨度>
  • 不要为 box-shadow 设置动画。而是将 box-shadow 属性移动到伪元素并为其不透明度和变换属性设置动画
  • @Denis move box-shadow property to pseudoelement and animate it's opacity and transform properties 我知道 OP 的问题已经很老了,但你能提供一个例子或参考吗?

标签: css


【解决方案1】:

是的,这是正常的,因为页面上有多个无限循环动画。因此,在渲染这些元素时,CPU 会不断地工作。有一个“神奇”属性会显着降低 CPU 使用率,那就是:

transform: translateZ(0);

这会将元素合成到它们自己的层中(通过诱使浏览器认为它会进行 3D 变换),并且在大多数情况下,浏览器应该利用 GPU 加速,从而减轻 CPU 的负担。对我来说,这减少了大约 20%(几乎一半)。

要了解有关此技术的更多信息,请查看:http://ariya.blogspot.com/2011/07/fluid-animation-with-accelerated.html

此外,动画中的关键帧越多,它也会越费力。只需尝试剪掉中间关键帧的动画,您就会看到 CPU 使用率再次大幅下降 (~10-12%)。

最后,并不是所有的属性都是相同的——box-shadow 比背景颜色更难让浏览器流畅地制作动画。在保留所有关键帧不变但删除 box-shadow 属性的情况下,使用 translateZ(0) 技巧让我的 CPU 使用率仅徘徊在 10-11%。

尽管这么说让我很痛苦,但对于无限循环动画,动画 .gif 在当前浏览器动画状态下的表现将比 CSS3 好得多,尤其是如果您计划保留其中的许多动画在页面上呈现一段时间。

2017 年更新:

对于那些仍在寻找解决此问题和答案的方法的人,translate3d(0, 0, 0) 提供与translateZ(0) 相同的好处,您只需同时设置translateX()translateY()。请忽略@Farside 的评论,因为他在演示中使用了translate3d(X, Y, Z),但没有将其与translate(X, Y) 进行比较,这表明使用这种技术仍然会有很大的不同。

根据this question,有些人发现transform: rotateZ(360deg) 在所有浏览器(尤其是Chrome)上都有更好的性能。

【讨论】:

  • 不,没有任何区别,在 Firefox 45.0.2 上试过,在 Chrome 50.0.2661 上试过。我认为即使没有类似translateZ(0) 的虚假转换,它也会尽可能多地应用 GPU。在我看来,现在使用 CSS 动画是个坏主意,因为 simple animations of trivial square 它会使 CPU 发热很多。
  • 当你的发现与我上面写的一致时,为什么要投反对票?您在该示例中运行了一个无限循环 - 我的 CPU 使用率在 10-14% 之间。您使用 translate3d 与使用 translatez(0) 相同 - 当您删除 CPU 使用率上升时。当然,它仍然会有所作为。
  • @Farside 请考虑编辑或删除您的评论,因为它绝对是错误的并提供错误信息。您的演示不会比较带有和不带有translateZ(0) 的动画,它只显示translate3d(x, y, z)。如果您将其与 translate(x, y) 进行比较,您会发现这种方法仍然存在显着差异。
  • 谢谢!将 CPU 负载从 170% (!) 降低到 13%。哇。
  • @skyline3000 translateZ 方法似乎并没有提高 macOS 上的性能。这是我的例子stackoverflow.com/questions/47296808/…
【解决方案2】:

在使用 CSS3 为某些元素设置动画时,我也遇到过类似的高 CPU 使用情况。我正在为大约 7 个元素的“左”属性设置动画,在我的整个页面中使用了一些不透明度和阴影属性。我决定改用 jQuery.animate,遗憾的是它根本没有提高性能。在显示页面时,我的 CPU (i7) 仍保持在 ~9-15%,一些技巧(translateZ 等)也没有真正提高性能 - 虽然我的布局搞砸了(涉及一些绝对定位的元素,哎哟!)。

然后我偶然发现了这个奇妙的扩展:http://playground.benbarnett.net/jquery-animate-enhanced/

我只是引用了 .js 文件,没有对 jQuery 转换进行任何更改,我的 CPU 使用率现在在同一页面上为 1-2%。

我的建议:当使用 CSS3 过渡遇到 CPU 问题时,切换到 jQuery + animate-enhanced-plugin。

【讨论】:

  • 在大多数情况下,许多项目不包含 jquery 作为依赖项,因此导入额外的包可能是不可接受的。
【解决方案3】:

您还可以在以下任何要使用 GPU 而不是 CPU 的类元素上使用它

.no-cpu {
    transform: translateZ(0);
    -webkit-transform: translateZ(0);
    -ms-transform: translateZ(0);
}

<element class="event_indicator no-cpu">animation...</element >

【讨论】:

  • 你忘记了'will-changes',你也应该把它重命名为'force-gpu',因为'no-cpu'非常不准确并且非常容易误导。
【解决方案4】:

减少 CPU 负载的一种可能方法是使用所谓的null transform hack,这通常被誉为灵丹妙药。在许多情况下,它将显着提高 WebKit 和 Blink 浏览器(如 Chrome、Opera 和 Safari)的渲染性能。

使用“Null tr​​ansform hack”(一种硬件合成模式)

null 转换 hack 基本上做了两件事:

  1. 它会打开硬件合成模式(假设平台支持)
  2. 它会创建一个具有自己的支持表面的新层

要“强制”浏览器,只需将以下 CSS 属性之一添加到元素:

transform: translateZ(0);

/* or its friend: */
transform: translate3d(0, 0, 0);

使用 3D 变换时,最好同时拥有这些属性to improve the performance

backface-visibility: hidden;
perspective: 1000;

“空变换黑客”的注意事项

在 CSS3 中为大量对象启用硬件加速可能会降低性能! 显然,每个空 3D 变换都会创建一个新图层。但是,强制黑客层创建可能并不总是解决页面上某些性能瓶颈的方法。层创建技术可以提高页面速度,但它们是有代价的:它们占用了系统 RAM 和 GPU 中的内存。因此,即使 GPU 做得很好,许多对象的传输也可能是一个问题,因此使用 GPU 加速可能不值得。来自W3C的引用:

但是,在新层中设置元素是一项相对昂贵的操作,它可以将变换动画的开始延迟明显的几分之一秒。

在使用 3D 加速时,移动一些大物体比移动大量小物体具有更高的性能。所以必须明智地使用它们,并且您需要确保硬件加速您的操作将真正有助于您的页面的性能,并且性能瓶颈不是由您页面上的另一个操作引起的。

此外,GPU 专为执行复杂的数学/几何计算而设计,将操作卸载到 GPU 会产生巨大的功耗。显然,当硬件启动时,目标设备的电池也会启动。

现代方式:will-change 属性

进步不是站在一个地方... W3C 引入了will-change CSS 属性。长话短说,will-change 属性允许您提前通知浏览器您可能对元素进行哪些类型的更改,以便它可以在需要之前设置适当的优化。

这是他们在draft 中所说的话:

本规范中定义的will-change 属性允许作者提前声明未来可能更改的属性,因此 UA 可以在需要它们之前的某个时间设置适当的优化。这样,当实际更改发生时,页面会以快速的方式更新。

使用will-change,向浏览器提示即将进行的转换可以很简单,只需将此规则添加到您希望转换的元素:

will-change: transform;

在针对移动设备进行开发时,开发人员在编写移动网络应用程序时不得不考虑各种设备限制。浏览器正变得越来越智能,有时,最好让平台本身做出决定,而不是重叠加速并以骇人听闻的方式强制行为。

【讨论】:

  • 它在MDN page 上声明“不要将 will-change 应用于太多元素。”和“谨慎使用”。在幕后,这个属性的当前浏览器实现很可能仍然只是组合元素。这个特性不仅是非标准的(它仍然是工作草案),它显然也不是你想要的“银弹”方法。此外,您的回答实际上并没有解释任何关于 OP 的 CPU 使用情况,也没有显示任何 CPU 使用情况的比较。
  • @skyline3000,我写了优点、缺点和警告。仔细阅读,will-change - 不是我的建议,但它是一种更优雅和现代的方式,“向浏览器提示即将进行的转换”,而不是强迫它。正如您所说,“被誉为银弹” - 属于所谓的null transform hack,而不是will-change 属性。我同意你的反对票,我知道你可能害怕竞争;)
【解决方案5】:

对于此处报告的“脉冲”背景动画的特殊情况,我提出了一个 css+js 解决方案。

在我的例子中,背景动画是在 background-position 属性上而不是在 background-color 上,但原理是一样的。

好的,假设您有一个具有特定背景的块:

<div class="nice-block">...</div>

让我们设置它的样式:(scss)

.nice-block {
  background-color: red;
  //or it can be: background: linear-gradient(45deg, #red, #white, #red);
  //and:          background-size: 600% 600%;

  //the transform and will-change properties
  //are here to only enable GPU
  transform: translateZ(0);
  -webkit-transform: translateZ(0);
  -ms-transform: translateZ(0);
  will-change: transform;

  transition: background-color 5s ease;
  //if you want to add a pulsing effect 
  //to a gradient, see the following two lines:
  // background-position: 0% 50%!important;
  // transition: background-position 5s ease;

  &.animated {
    background-color: white;
    //and in case of gradient animation:
    // background-position: 100% 50%!important;
  }
}

现在是时候通过使用一些 JavaScript 向块中添加一个“动画”类来实现效果了:

var bgAnimateTimer;
function animateBg () {
  clearTimeout(bgAnimateTimer);
  bgAnimateTimer = setTimeout(function () {
    clearTimeout(bgAnimateTimer);
    bgAnimateTimer = setTimeout(function () {

      document.querySelector('.nice-block').classList.toggle('animated');

      //jQuery alternative is:
      // $('.nice-block').toggleClass('animated');

      animateBg ();
    }, 5000); //5 seconds for the animation effect
  }, 2500); //2.5 seconds between each animation
}

animateBg ();

这将我的性能提高了约 15 倍。

(i) 如果您想要不同于 5 秒的值,请注意在 css 和 js 中正确计算转换和超时的秒数。

【讨论】:

    猜你喜欢
    • 2016-01-23
    • 1970-01-01
    • 1970-01-01
    • 2014-08-28
    • 1970-01-01
    • 2018-02-07
    • 2013-08-04
    • 2021-12-08
    相关资源
    最近更新 更多