CSS关键帧动画CPU使用率很高,应该采用这种方式吗?


78

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

@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/


1
根据Chrome任务管理器,除了CPU较高以外,它似乎还与不断增加的内存占用量有关。
凯文·布洛维

@KevinBullaughey,显然,每个对象都有代价:它们占用系统RAM和/或GPU上的内存,请参阅说明,加上动画本身是一个相对昂贵的操作!
远端

2
不要为盒子阴影设置动画。而是将box-shadow属性移动到伪元素并对其不透明度进行动画处理并变换属性
Denis

@Denismove box-shadow property to pseudoelement and animate it's opacity and transform properties我知道OP的问题已经很老了,但是您能提供一个例子还是参考?
tonix

Answers:


89

是的,这很正常,因为页面上有几个无限循环动画。因此,在渲染这些元素时,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属性,使用translateZ(0)技巧可使我的CPU使用率仅徘徊在10-11%之间。

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

2017年更新:

对于那些仍在寻找他们的这一问一答的方式,translate3d(0, 0, 0)提供同样的好处是translateZ(0),你只是还设置translateX()translateY()在同一时间。请忽略@Farsidetranslate3d(X, Y, Z)在演示中使用的评论,但不要将其与进行比较translate(X, Y),这表明使用此技术仍会产生很大的不同。

根据这个问题,有人发现,所有浏览器(尤其是Chrome)的性能都更好transform: rotateZ(360deg)


3
不,它不再有任何区别,在Firefox 45.0.2上尝试过,在Chrome 50.0.2661中尝试过。我认为即使没有伪转换,它也会尽可能多地使用GPU translateZ(0)。在我看来,现在使用CSS动画似乎不是一个好主意,因为琐碎的正方形简单动画会极大地消耗CPU。
远端

1
如果您的发现与我上面写的内容一致,为什么还要投票?在该示例中,您正在运行一个无限循环-我的CPU使用率在10%至14%之间。您使用了translate3d,与使用translatez(0)相同-删除后,CPU使用率上升。当然,它仍然会有所作为。
skyline3000

4
@Farside请考虑编辑或删除您的评论,因为它肯定是错误的,并提供了错误的信息。您的演示不比较有和没有动画translateZ(0),它只显示translate3d(x, y, z)。如果将它与just进行比较translate(x, y),您会看到此方法仍然产生了显着差异。
skyline3000

1
谢谢!将CPU负载从170%(!)降低到13%。哇。
Zack Katz

1
@ skyline3000 translateZ方法似乎无法提高macOS的性能。这是我的示例stackoverflow.com/questions/47296808/…–
Winston

15

减轻CPU负载的一种可能方法是使用所谓的null transform hack,通常被誉为“银弹”。在许多情况下,它将大大提高WebKit和Blink浏览器(例如Chrome,Opera和Safari)的渲染性能。

“空变换黑客”的使用(硬件合成模式)

空转换黑客基本上可以做两件事:

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

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

transform: translateZ(0);

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

使用3D变换时,最好同时具有以下属性以提高性能

backface-visibility: hidden;
perspective: 1000;

“空变换黑客”的警告

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

但是,将元素设置在新的图层中是相对昂贵的操作,这可能会使转换动画的开始延迟明显的几分之一秒。

与使用3D加速时移动许多小物件相比,移动一些大物件具有更高的性能。因此,必须明智地使用它们,并且您需要确保硬件加速操作确实可以帮助提高页面的性能,并且确保性能瓶颈不是由页面上的其他操作引起的。

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

现代方式:will-change财产

进展并不仅仅停留在一个地方... W3C引入了will-changeCSS属性。简而言之,该will-change属性允许您提前通知浏览器您可能会对元素进行哪些更改,以便可以在需要之前进行适当的优化。

他们在草案中说的是:

通过will-change本规范中定义的属性,作者可以提前声明将来可能会更改的属性,因此UA可以在需要它们之前的某个时间进行适当的优化。这样,当实际更改发生时,页面会迅速更新。

使用will-change,向浏览器提示即将进行的转换就像将以下规则添加到您希望转换的元素中一样简单:

will-change: transform;

在为移动设备进行开发时,开发人员被迫在编写移动Web应用程序时考虑各种设备限制。浏览器变得越来越聪明,有时候,最好将决定权留给平台本身,而不是重叠加速并以骇人的方式强迫行为。


它在MDN页面上指出“不要将遗嘱更改应用于太多元素”。和“谨慎使用”。在幕后,此属性的当前浏览器实现很可能仍旧只是组合元素。此功能不仅是非标准的(仍然是工作草案),而且显然也不是您要成为的“银弹”方法。此外,您的答案实际上并没有解释关于OP的CPU使用率的任何内容,也没有显示任何CPU使用率的比较。
skyline3000

2
@ skyline3000,我写了优点,缺点和警告。请仔细阅读will-change-不是我的推荐,但它是“向浏览器提示即将发生的转换”而不是强制执行的更为优雅和现代的方式。“被誉为银弹”-属于所谓的null transform hack,而不是will-change您声明的财产。我对您的不赞成票表示满意,我知道您可能会害怕竞争;)
Farside

4

使用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。


1
在大多数情况下,许多项目不包含jquery作为依赖项,因此导入额外的包可能是不可接受的。
Dimitris Filippou

3

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

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

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

1
您忘记了“意愿变更”,还应将其重命名为“ force-gpu”,因为“ no-cpu”非常不准确且极具误导性。

1

对于此处报告的“脉动”背景动画的特殊情况,我想出了一个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中正确计算过渡和超时的秒数。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.