提高 CSS3 背景位置动画的性能



我正在尝试改进CSS3动画,因为当前代码似乎导致了一些过度的CPU负载,浏览器似乎很滞后。

我能做什么?我有所有的供应商前缀等等。我不确定我能不能改进代码或重构它以将其用作最佳代码实践。

Fiddle演示

.wrapper {
  width: 960px;
  height: 140px;
  margin-top: 80px;
  position: relative;
}
.content:before {
  position: absolute;
  z-index: 1;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  content: "";
  -webkit-transform: translateZ(0);
  transform: translateZ(0);
  -webkit-transform-origin: 50% 50% 0;
  -ms-transform-origin: 50% 50% 0;
  transform-origin: 50% 50% 0;
  v -webkit-animation-name: sideupscroll;
  animation-name: sideupscroll;
  /*animation-duration*/
  -webkit-animation-duration: 80s;
  animation-duration: 80s;
  /*animation-timing-function*/
  -webkit-animation-timing-function: linear;
  animation-timing-function: linear;
  /*animation-iteration-count*/
  -webkit-animation-iteration-count: infinite;
  animation-iteration-count: infinite;
  background: url("http://i.imgur.com/wNna7D3.png") repeat fixed 0 0 indigo;
  -webkit-animation-fill-mode: both;
  animation-fill-mode: both;
}
/* Safari and Chrome */
@-webkit-keyframes sideupscroll {
  0% {
    background-position: 0 0;
  }
  50% {
    background-position: -50% -100%;
  }
  100% {
    background-position: -100% -200%;
  }
}
@keyframes sideupscroll {
  0% {
    background-position: 0 0;
  }
  50% {
    background-position: -50% -100%;
  }
  100% {
    background-position: -100% -200%;
  }
}
<div class="wrapper">
  <div class="content"></div>
</div>

原因

为元素的background-position设置动画总是资源密集型的,而且在几乎所有浏览器中都很有可能导致动画滞后。这是因为,对background-position的更改会导致在所有浏览器中重新绘制+合成(+还会导致在Webkit中重新布局(。由于需要执行如此多昂贵的操作,结果总是滞后。

有问题的代码段:

下面的代码段与您的fiddle相同(没有供应商前缀(。在启用"Show Paint Rects"选项后,运行此代码段并使用Chrome Dev工具进行检查。您会在元素顶部看到一个红色或绿色的框(这是绘制矩形(,该框将持续闪烁,或者在整个动画期间保持彩色。这表明重新绘制经常发生,因此会影响性能。

在Firefox中,可以通过在about:config页面中启用nglayout.debug.paint_flashing(将其设置为true(来查看绘制矩形。

.wrapper {
  width: 960px;
  height: 140px;
  margin-top: 80px;
  position: relative;
}
.content:before {
  position: absolute;
  z-index: 1;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  content: "";
  transform: translateZ(0);
  transform-origin: 50% 50% 0;
  animation-name: sideupscroll;
  animation-duration: 80s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  background: url("http://i.imgur.com/wNna7D3.png") repeat fixed 0 0 indigo;
  animation-fill-mode: both;
}
@keyframes sideupscroll {
  0% {
    background-position: 0 0;
  }
  50% {
    background-position: -50% -100%;
  }
  100% {
    background-position: -100% -200%;
  }
}
<div class="wrapper">
  <div class="content"></div>
</div>


解决方案

最好避免为background-*属性(所有属性都是视觉属性(设置动画,并使用类似transform的属性。使用transform至少在Blink(Chrome(和EdgeHTML中产生更好的性能,因为Blink只进行重新组合,而EdgeHTML只第一次触发重新布局(动画中的第一次更新(。

没有问题的代码段:(或至少对Blink和EdgeHTML性能的影响小得多(

下面的代码段使用transform属性(translateXtranslateY(来实现与预期输出非常相似(但不相同(的内容。如果您使用开发工具检查这个片段,您会看到绿框(paint-rect(在动画开始时只出现一次。之后,浏览器只执行合成,因此性能要好得多。

.wrapper {
  width: 960px;
  height: 140px;
  margin-top: 80px;
  position: relative;
  overflow: hidden;
}
.content:before {
  position: absolute;
  z-index: 1;
  top: 0;
  left: 0;
  width: 200%;
  height: 400%;
  content: "";
  background: url("http://i.imgur.com/wNna7D3.png") 0 0 indigo;
  background-repeat: repeat;
}
.content {
  position: relative;
  height: 100%;
  width: 100%;
  animation-name: sideupscroll;
  animation-duration: 80s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  animation-fill-mode: both;
}
@keyframes sideupscroll {
  0% {
    transform: translateX(0%) translateY(0%);
  }
  50% {
    transform: translateX(-50%) translateY(-100%);
  }
  100% {
    transform: translateX(-100%) translateY(-200%);
  }
}
<div class="wrapper">
  <div class="content"></div>
</div>

壁虎和Webkit怎么样

不幸的是,在撰写本文时,还没有针对使用这些渲染引擎的浏览器的解决方案。唯一的选择似乎是减少animation-duration。动画持续时间的减少意味着所需的重新绘制+重新布局+重新构图周期的数量更少,因此动画的性能更好。

下面的片段在Firefox中看起来不那么拖沓,因为持续时间只有20秒。

.wrapper {
  width: 960px;
  height: 140px;
  margin-top: 80px;
  position: relative;
  overflow: hidden;
}
.content:before {
  position: absolute;
  z-index: 1;
  top: 0;
  left: 0;
  width: 200%;
  height: 400%;
  content: "";
  background: url("http://i.imgur.com/wNna7D3.png") 0 0 indigo;
  background-repeat: repeat;
}
.content {
  position: relative;
  height: 100%;
  width: 100%;
  animation-name: sideupscroll;
  animation-duration: 20s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  animation-fill-mode: both;
}
@keyframes sideupscroll {
  0% {
    transform: translateX(0%) translateY(0%);
  }
  50% {
    transform: translateX(-50%) translateY(-100%);
  }
  100% {
    transform: translateX(-100%) translateY(-200%);
  }
}
<div class="wrapper">
  <div class="content"></div>
</div>

有用链接:

  • CSS触发器-列出哪些属性导致触发哪些操作
  • HTML5 Rocks-Chrome中的加速渲染-解释加速渲染在Chrome中的工作原理(以及如何启用"显示绘制矩形"选项(

注意:如上所述,动画与您所讨论的内容并非100%相同,但在我看来,这是最接近的。

最新更新