浏览器渲染
提高动画的优化不得不提及浏览器是如何渲染一个页面。在从服务器中拿到数据后,浏览器会先做解析三类东西:
- 解析
html,xhtml,svg
这三类文档,形成dom
树。 - 解析
css
,产生css rule tree
。 - 解析
js
,js
会通过api
来操作dom tree
和css rule tree
。
解析完成之后,浏览器引擎会通过dom tree
和css rule tree
来构建rendering tree
:
rendering tree
和dom tree
并不完全相同,例如:<head></head>
或display:none
的东西就不会放在渲染树中。css rule tree
主要是完成匹配,并把css rule
附加给rendering tree
的每个element
。
在渲染树构建完成后,
- 浏览器会对这些元素进行定位和布局,这一步也叫做
reflow
或者layout
。 - 浏览器绘制这些元素的样式,颜色,背景,大小及边框等,这一步也叫做
repaint
。 - 然后浏览器会将各层的信息发送给
GPU
,GPU
会将各层合成;显示在屏幕上。
reflow => repaint => composite
reflow
和repaint
都是耗费浏览器性能的操作,为了仅发生composite
,我们做动画的css property
必须满足以下三个条件:
- 不影响文档流。
- 不依赖文档流。
- 不会造成重绘。
满足以上以上条件的css property
只有transform
和opacity
。
这样做有两个优势:
- 动画将会非常流畅
- 动画不在绑定到CPU,即使js执行大量的工作;动画依然流畅。
GPU
有2个问题:
一个或多个没有自己复合层的元素要出现在有复合层元素的上方,它就会拥有自己的复合层;这种情况被称为隐式合成。
使用GPU
动画需要发送多张渲染层的图像给GPU
,GPU
也需要缓存它们以便于后续动画的使用。
优化技巧
- 保持动画的对象的
z-index
尽可能的高。理想的,这些元素应该是body
元素的直接子元素。当然,这不是总可能的。所以你可以克隆一个元素,把它放在body
元素下仅仅是为了做动画。 - 将元素上设置
will-change
CSS属性,元素上有了这个属性,浏览器会提升这个元素成为一个复合层(不是总是)。这样动画就可以平滑的开始和结束。但是不要滥用这个属性,否则会大大增加内存消耗。
用css
动画而不是js
动画
css
动画有一个重要的特性,它是完全工作在GPU
上。因为你声明了一个动画如何开始和如何结束,浏览器会在动画开始前准备好所有需要的指令;并把它们发送给GPU
。而如果使用js
动画,浏览器必须计算每一帧的状态;为了保证平滑的动画,我们必须在浏览器主线程计算新状态;把它们发送给GPU
至少60
次每秒。除了计算和发送数据比css
动画要慢,主线程的负载也会影响动画; 当主线程的计算任务过多时,会造成动画的延迟、卡顿。
所以尽可能地使用基于css
的动画,不仅仅更快;也不会被大量的js计算所阻塞。
总结:使用transform
和 will-change
能开启GPU
。