87

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

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

4

5 回答 5

99

是的,这很正常,因为页面上有几个无限循环动画。因此,在渲染这些元素时,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),这表明使用这种技术仍然会产生重大影响。

根据这个问题,有些人发现在所有浏览器,尤其是 Chrome 中,使用transform: rotateZ(360deg).

于 2012-11-08T16:17:33.170 回答
19

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

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

空变换 hack 基本上做了两件事:

  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 应用程序时不得不考虑广泛的设备限制。浏览器变得越来越聪明,有时,最好让平台本身来决定,而不是重叠加速并以一种骇人听闻的方式强迫行为。

于 2017-01-23T00:45:05.060 回答
5

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

于 2013-05-02T11:11:23.593 回答
3

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

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

<element class="event_indicator no-cpu">animation...</element >
于 2016-04-08T01:15:48.447 回答
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 中正确计算转换和超时的秒数。

于 2019-10-09T16:53:08.403 回答