CSS CSS关键帧动画CPU占用率高,应该这样吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13176746/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
CSS keyframe animation CPU usage is high, should it be this way?
提问by Ilya Tsuryev
I use following keyframe animation on several elements:
我在几个元素上使用以下关键帧动画:
@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;
}
On my computer I am getting around 40% CPU usage both in Chrome and Firefox. Is it the current state of animations (nice but not usable for now) or am I missing some magic property?
在我的电脑上,Chrome 和 Firefox 的 CPU 使用率都在 40% 左右。它是动画的当前状态(不错但现在不可用)还是我错过了一些魔法属性?
You can check the following sample with the same animation: http://jsfiddle.net/Nrp6Q/
您可以使用相同的动画检查以下示例:http: //jsfiddle.net/Nrp6Q/
回答by skyline3000
Yes, this is normal because you have several infinite-loop animations on the page. The CPU is therefore continually doing work while these elements are rendered. There is a "magic" property that will significantly cut-down the CPU usage and that is:
是的,这是正常的,因为页面上有多个无限循环动画。因此,在渲染这些元素时,CPU 会持续工作。有一个“神奇”属性可以显着降低 CPU 使用率,即:
transform: translateZ(0);
This will composite the elements into their own layers (by tricking the browser into thinking it will be doing 3D transforms) and the browser should, in most cases, take advantage of GPU acceleration, lessening the burden on the CPU. For me this cut it down by about 20% (almost half).
这会将元素合成到它们自己的层中(通过诱使浏览器认为它将进行 3D 转换),并且在大多数情况下,浏览器应该利用 GPU 加速,减轻 CPU 的负担。对我来说,这减少了大约 20%(几乎一半)。
To read more about this technique take a look at: http://ariya.blogspot.com/2011/07/fluid-animation-with-accelerated.html
要了解有关此技术的更多信息,请查看:http: //ariya.blogspot.com/2011/07/fluid-animation-with-accelerated.html
Additionally, the more keyframes you have in the animation, the more taxing it will be as well. Just try the animation with the middle keyframe cut out and you will see another substantial (~10-12%) drop in CPU usage.
此外,动画中的关键帧越多,也就越费力。只需尝试剪掉中间关键帧的动画,您就会看到 CPU 使用率再次大幅下降(约 10-12%)。
Lastly, not all properties are equal -- box-shadow is much harder for the browser to animate smoothly than, say, background-color. Leaving all of the keyframes intact but dropping the box-shadow property, using the translateZ(0) trick had my CPU usage hovered at only 10-11%.
最后,并非所有属性都是相同的——对于浏览器来说,box-shadow 比 background-color 更难平滑动画。保留所有关键帧完整但删除 box-shadow 属性,使用 translateZ(0) 技巧使我的 CPU 使用率仅徘徊在 10-11%。
As much as it pains me to say this, for infinite-loop animations an animated .gif is going to perform much, much better than CSS3 in the current state of browser animation, especially if you plan for many of them to remain rendered on the page for some time.
尽管我这么说很痛苦,但对于无限循环动画,在当前浏览器动画状态下,动画 .gif 的性能将比 CSS3 好得多,尤其是如果您计划将它们中的许多保持在页面一段时间。
Update 2017:
2017 年更新:
For those still finding their way to this question and answer, translate3d(0, 0, 0)
provides the same benefit as translateZ(0)
, you're just also setting translateX()
and translateY()
at the same time. Please ignore the comment by @Farsideas he uses translate3d(X, Y, Z)
in his demo but does not compare it to translate(X, Y)
, which would show that using this technique still makes a significant difference.
对于那些仍在寻找他们的这一问一答的方式,translate3d(0, 0, 0)
提供同样的好处是translateZ(0)
,你只是还设置translateX()
并translateY()
在同一时间。请忽略@Farsidetranslate3d(X, Y, Z)
在他的演示中使用的评论,但未将其与 进行比较translate(X, Y)
,这表明使用此技术仍然会产生显着差异。
According to this question, some people have found better performance across all browsers, especially Chrome, with transform: rotateZ(360deg)
.
根据这个问题,有些人发现使用transform: rotateZ(360deg)
.
回答by Farside
One of the possible ways to reduce the load on CPU, is to use a so called null transform hack
, which is often hailed as something of a silver bullet. In many cases it will drastically improve rendering performance in WebKit and Blink browsers like Chrome, Opera and Safari.
减少 CPU 负载的一种可能方法是使用所谓的null transform hack
,它通常被誉为灵丹妙药。在许多情况下,它将显着提高 WebKit 和 Blink 浏览器(如 Chrome、Opera 和 Safari)的渲染性能。
Usage of the "Null transform hack" (a hardware compositing mode)
使用“Null transform hack”(一种硬件合成模式)
The null transform hack basically does two things:
空变换 hack 基本上做了两件事:
- It switches on the hardware compositing mode(assuming it's supported for the platform)
- It creates a new layer with its own backing surface
- 它打开硬件合成模式(假设平台支持它)
- 它创建了一个具有自己的背衬表面的新层
To "force" a browser, simply add one of these CSS properties to the element:
要“强制”浏览器,只需将以下 CSS 属性之一添加到元素:
transform: translateZ(0);
/* or its friend: */
transform: translate3d(0, 0, 0);
When working with 3D transforms, it's good to have these properties as well to improve the performance:
使用 3D 变换时,最好使用这些属性来提高性能:
backface-visibility: hidden;
perspective: 1000;
Caveats of the "null transform hack"
“空变换黑客”的注意事项
Enabling a hardware acceleration in CSS3 for a lot of objects may slow down performance!Apparently, each null 3D transform creates a new layer. However, force-hacking layer creation may not always be the solution to certain performance bottlenecks on a page. Layer creation techniques can boost page speed, but they come with a cost: they take up memory in system RAM and on the GPU. So even if the GPU does a good job, the transfer of many objects might be a problem so that using GPU acceleration might not be worth it. The cite from W3C:
在 CSS3 中为许多对象启用硬件加速可能会降低性能!显然,每个空 3D 变换都会创建一个新层。但是,强制黑客层创建可能并不总是解决页面上某些性能瓶颈的方法。层创建技术可以提高页面速度,但它们需要付出代价:它们会占用系统 RAM 和 GPU 上的内存。因此,即使 GPU 做得很好,许多对象的传输也可能是一个问题,因此使用 GPU 加速可能不值得。来自W3C的引用:
However, setting up the element in a fresh layer is a relatively expensive operation, which can delay the start of a transform animation by a noticeable fraction of a second.
然而,在新层中设置元素是一项相对昂贵的操作,它可以将变换动画的开始延迟明显的几分之一秒。
Moving a few big objects has a higher performance, than moving lots of small items when using 3D-acceleration. So they must be used wiselyand you need to make sure that hardware-accelerating your operation will really help the performance of your page, and that a performance bottleneck is not being caused by another operation on your page.
在使用 3D 加速时,移动一些大物体比移动大量小物体具有更高的性能。因此,必须明智地使用它们,并且您需要确保硬件加速您的操作确实有助于提高页面的性能,并且性能瓶颈不是由页面上的其他操作引起的。
Moreover, a GPU is designed specifically for performing the complex mathematical/geometric calculations, and offloading operations onto the GPU can yield massive power consumption. Obviously, when hardware kicks in, so does the battery of the target device.
此外,GPU 专为执行复杂的数学/几何计算而设计,将操作卸载到GPU 会产生大量功耗。显然,当硬件启动时,目标设备的电池也会启动。
The modern way: the will-change
property
现代方式:will-change
物业
The progress is not standing on the one place... W3C introduced the will-change
CSS property. To cut the long story short, the will-change
property allows you to inform the browser ahead of time of what kinds of changes you are likely to make to an element, so that it can set up the appropriate optimizations before they're needed.
进步不是站在一个地方... W3C引入了will-change
CSS属性。长话短说,该will-change
属性允许您提前通知浏览器您可能对元素进行哪些类型的更改,以便它可以在需要之前设置适当的优化。
Here's what they say in the the draft:
这是他们在草案中所说的:
The
will-change
property defined in this specification allows an author to declare ahead-of-time what properties are likely to change in the future, so the UA can set up the appropriate optimizations some time before they're needed. This way, when the actual change happens, the page updates in a snappy manner.
will-change
本规范中定义的属性允许作者提前声明哪些属性将来可能会更改,因此 UA 可以在需要它们之前的某个时间设置适当的优化。这样,当实际更改发生时,页面会以快速的方式更新。
Using will-change
, hinting to the browser about an upcoming transformation can be as simple as adding this rule to the element that you're expecting to be transformed:
使用will-change
, 向浏览器提示即将进行的转换就像将此规则添加到您希望转换的元素一样简单:
will-change: transform;
When developing for mobile, developers are forced to take the wide array of device constraints into consideration while writing mobile web apps. Browsers are becoming smarter, and sometimes, it's better to leave the decision to the platform itself, instead of overlapping acceleration and forcing the behavior in a hacky-way.
在为移动设备进行开发时,开发人员在编写移动 Web 应用程序时被迫考虑各种设备限制。浏览器变得越来越智能,有时,最好将决定权留给平台本身,而不是重叠加速并以骇人听闻的方式强制行为。
回答by konrad_pe
I had a similar case of high CPU usage when animating some elements with CSS3. I was animating the "left"-property of ~7 elements, with some opacity- and shadow-properties used in my whole page. I decided to switch to jQuery.animate, which sadly didn't improve the performance at all. My CPU (i7) was still at ~9-15% while displaying the page, several tricks (translateZ, etc) didn't really improve the performance either - while having my layout messed up (some absolute-positioned elements were involved, ouch!).
在使用 CSS3 为某些元素设置动画时,我遇到了类似的 CPU 使用率过高的情况。我正在为 ~7 个元素的“左”属性设置动画,在我的整个页面中使用了一些不透明度和阴影属性。我决定切换到 jQuery.animate,遗憾的是它根本没有提高性能。我的 CPU (i7) 在显示页面时仍然在 ~9-15%,几个技巧(translateZ 等)也没有真正提高性能 - 同时我的布局搞砸了(涉及一些绝对定位的元素,哎哟!)。
Then I stumbled upon this wonderful extension: http://playground.benbarnett.net/jquery-animate-enhanced/
然后我偶然发现了这个美妙的扩展:http: //playground.benbarnett.net/jquery-animate-enhanced/
I simply referenced the .js-file, didn't make a single change at the jQuery transitions, and my CPU usage is now 1-2% on the very same page.
我只是引用了 .js 文件,在 jQuery 转换时没有做任何更改,我的 CPU 使用率现在在同一页面上为 1-2%。
My recommendation: when facing CPU issues using CSS3 transitions, switch to jQuery + the animate-enhanced-plugin.
我的建议:当使用 CSS3 转换遇到 CPU 问题时,切换到 jQuery + animate-enhanced-plugin。
回答by user1467439
You can also use this on any of the following class elements where you want to use GPU instead of CPU
您还可以在以下任何要使用 GPU 而不是 CPU 的类元素上使用它
.no-cpu {
transform: translateZ(0);
-webkit-transform: translateZ(0);
-ms-transform: translateZ(0);
}
<element class="event_indicator no-cpu">animation...</element >
回答by Oleg K
To a particular case of 'pulsing' background animation, reported here, I've come up with a css+js solution.
对于此处报告的“脉冲”背景动画的特殊情况,我提出了一个 css+js 解决方案。
In my case the background animation was on background-position property rather than on the background-color, but the principle is the same.
在我的例子中,背景动画是在 background-position 属性上而不是在 background-color 上,但原理是一样的。
Ok, let's say you have a block with a particular background:
好的,假设您有一个具有特定背景的块:
<div class="nice-block">...</div>
Let's style it: (scss)
让我们设计它:(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;
}
}
Now it's time to make the effect happen by adding a class 'animated' to the block with some JavaScript:
现在是时候通过使用一些 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 ();
This improved performace in my case by ~15 times.
在我的情况下,这将性能提高了约 15 倍。
(i) Note to calculate seconds for transition and timeouts correctly both in css and js if you want values different from 5 seconds.
(i) 如果您希望值不同于 5 秒,请注意在 css 和 js 中正确计算转换和超时的秒数。