CSS3动画之硬件加速

div {
  transform: translate3d(0,0,0);
}

在移动端,我们经常用到如上的CSS代码实现所谓的“硬件加速”,来提高动画的流畅度。在部分情况下,我们的CSS动画的确变的更加流畅。但这个方法并不是万能药。当页面中加速的元素越来越多时,网页的性能便会下降。为了更详细的了解原因,我们有必要了解下浏览器的内部机制。

浏览器内部渲染机制

现在的浏览器通常会有两个重要的执行线程,这2个线程协同工作来渲染一个网页。

  • 主线程
  • 合成线程

一般情况,主线程负责:

  • 运行JavaScript: JavaScript实现动画效果,DOM元素操作等
  • 计算CSS样式:确定每个DOM元素应该用什么CSS规则
  • 布局: 计算每个DOM元素在最终屏幕上显示的大小和位置。由于web页面的元素布局是相对的,所以其中任意一个元素的位置发生变化,都会联动的引起其他元素发生变化,这个过程叫reflow。
  • 绘制:在多个层上绘制DOM元素的文字,颜色,图像,边框和阴影等。
  • 将位图移交给合成线程

相应地,合成线程负责:

  • 通过GPU将位图绘制到屏幕上
  • 通知主线程更新页面中可见或即将变成可见的部分的位图
  • 计算出页面中哪部分是可见的
  • 计算出当你在滚动页面时哪部分是即将变成可见的
  • 当你滚动页面时将相应位置的元素移动到可视区域

两者之间的关系:长时间执行 JavaScript 或渲染一个很大的元素会阻塞主线程,在这期间,它将无法响应用户的交互。相反,合成线程则会尽量去响应用户的交互。当一个页面发生变化时,合成线程会以每秒60 帧的间隔去不断重绘这个页面,即使这个页面不完整。

举个例子,当用户滚动页面时,合成线程会通知主线程更新页面中最新可见部分的位图。但是,如果主线程响应地不够快,合成线程不会保持等待,而是马上绘制已经生成的位图,还没准备好的部分用白色进行填充。

刚才提到了合成线程会使用GPU将位图绘制到屏幕上,接下来让我们了解下GPU

硬件加速GPU

GPU优势

  • 绘制位图到屏幕上
  • 将同一位图绘制到不同位置,执行旋转以及缩放处理

GPU弱势

  • 将位图加载到它的内存中

为什么要关心硬件加速GPU
先来看第一个例子:

div {
  height: 100px;
  transition: height 1s linear;
}
div:hover {
  height: 200px;
}

一个从height:100px 到 height:200px 的动画按照下面的流程图来执行各种操作,注意在橘黄色方框的操作可能会比较耗时,在绿色框中的操作是比较快速的。


CSS3动画之硬件加速_第1张图片
animation-height.png

正如你所看到的,上图中很多橘黄色的方框,意味着,浏览器需要做大量的工作。浏览器需要做大量工作的原因在于每一帧中元素的内容都在不断改变。在动画的每一帧中,浏览器都要执行布局、 绘制、 以及将新的位图提交给 GPU。改变一个元素的高度可能导致需要同步改变它的子元素的大小,所以浏览器必须重新计算布局。布局完成后,主线程又必须重新生成该元素的位图。

再来看第二个例子:

div { 
  transform: scale(0.5); 
  transition: transform 1s linear;
}
div:hover { 
  transform: scale(1.0);
}

让我们看看这种情况下的流程图:


CSS3动画之硬件加速_第2张图片
animation-transform.png

这次我们可以看到少了很多橙色的方框,意味着动画变得更流畅了!那么,为什么执行一个元素的transform动画会跟height动画表现得不一样呢?这是因为transform 属性不会触发浏览器的repaint, 而height会一直触发repaint。

硬件加速GPU的工作原理
浏览器接收到页面文档后,会将文档中的标记语言解析为DOM树。DOM树和CSS结合后形成浏览器构建页面的渲染树。渲染树中包含了大量的渲染元素,每一个渲染元素会被分到一个图层中,每个图层又会被加载到GPU形成渲染纹理,而图层在GPU中 transform是不会触发 repaint 的,这一点非常类似3D绘图功能,最终这些使用 transform的图层都会由独立的合成器进程进行处理。

触发硬件加速GPU的渲染元素
transform
opacity
filter

强制使用GPU渲染

.example1 {
  transform: translateZ(0);
}
.example2 { 
  transform: rotateZ(360deg);
}

这段代码的作用就是让浏览器执行 3D transform。浏览器通过该样式创建了一个独立图层,图层中的动画则有GPU进行预处理并且触发了硬件加速。

使用硬件加速的注意事项

  • 内存:如果GPU加载了大量的纹理,那么很容易就会发生内容问题,这一点在移动端浏览器上尤为明显,所以,一定要牢记不要让页面的每个元素都使用硬件加速。
  • 使用2D的transform,在动画开始和结束的时候会发生两次repaint操作。3D 和 2D transform 的区别就在于,浏览器在页面渲染前为3D动画创建独立的复合图层,而在运行期间为2D动画创建。动画开始时,生成新的复合图层并加载为GPU的纹理用于初始化 repaint。然后由GPU的复合器操纵整个动画的执行。最后当动画结束时,再次执行 repaint 操作删除复合图层。

参考文献:
http://zencode.in/14.CSS%E5%8A%A8%E7%94%BB%E7%9A%84%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96.html
http://blog.csdn.net/leer168/article/details/25917093
http://www.w3cplus.com/css3/introduction-to-hardware-acceleration-css-animations.html
https://github.com/ccforward/cc/issues/42
http://alexorz.github.io/animation-performance-guide/

你可能感兴趣的:(CSS3动画之硬件加速)