图层重绘与重排
css图层
浏览器再渲染一个页面时,会将页面分为很多个图层,图层有大有小,每个图层上又一个或多个节点,在渲染DOM的时候,浏览器所做的工作实际上时:
- 获取dom分割为多个图层
- 对每个图层的节点计算样式的结果(Recalculate style–样式重计算)
- 为每个节点生成图形和位置(layout—重排,回流)
- 将每个节点绘制填充到图层位图中(paint—重绘)
- 图层作为纹理上传到GPU
- 组合多个图层到页面上生成最终屏幕图像 (Composite-layers–图层重组)
图层创建的条件
chrome浏览器满足一下任何情况都会创建图层
- 拥有3D变换的CSS属性
- 使用加速视频解码的节点
- 节点
- CSS3动画的节点
- 用偶遇加速属性的元素(will-change)
重绘(Repaint)
重绘是一个元素外观的改变所触发的浏览器行为,例如outline,背景色等属性,浏览器会根据元素的新属性重新绘制,使元素呈现新的外观,重绘不会带来重新布局,所以不一定伴随重排。
需要注意的是:重绘是以图层为单位,如果图层中某个元素需要重绘,那么整个图层都需要重绘,比如一个图层包含很多节点,其中有个gif图gif图的每一帧,都会重绘整个涂层的其他节点,然后生成最终的图层位图。所以这需要通过特殊的方式来强制gif图属于自己一个图层(translateZ(0)或者translate3d(0,0,0)css3的动画也是意昂(好在大的部分情况浏览器自己会为css3动画的节点创建图层)
重排(Reflow 回流)
渲染对象在创建完成添加到渲染树时,并不包含位置的大小信息,计算这些值的过程称为布局或者重拍
“重绘”不一定需要“重排,比如改变某个元素网页元素的颜色,就只会触发“重绘”,不会触触发“重排“,但是,”重排“必然导致”重绘“,比如改变一个网页元素的位置,就会同时触发”重排“和”重绘“,因为布局改变了
触发重绘的属性
属性影响元素的外观,颜色,阴影,边框就会触发重绘
触发重排的属性
元素的宽高属性,位置,字体大小,字体样式,对齐方式改变了就会引起重排
常见的触发重排的操作
Relflow 的成本相比Repaint成本大的多,DOM树李的每个节点都会有Reflow方法,一个节点的Reflow很有可能导致子节点,甚至父节点以及同级节点的Reflow,在一些高性能的电脑上也许还没什么,但是如果Reflow发生在手机上这个过程事非常痛苦,非常好点的
所以,下面这些操作很大可能会是成本比较高的
当你增加、删除、修改DOM节点时,导致Reflow、Repaint
当你移动DOM的位置
当你Resize窗口的时候(移动端没有这个问题,因为移动端的缩放没有影响布局视口 )
当年你修改网页的默认字体的时,
获取某些属性时(wiidth,height。。。)
> 注:display:none会触发reflow ,而visibility:hidden指挥触发repaint,因为没有发生位置变化
优化方案
如果我们需要使得动画或其他节点渲染的性能提高,需要做的就是减少浏览器在运行时所需要做的工作(j尽量减少234步)
1. 计算需要被加载到节点上的样式结果(Recalcutlate style--样式重计算)
2. 为每个节点生成图形和位置(layout--回流和重布局)
3. 将每个节点填充到图层中(paint setup 和paint--重绘)
4. 组合图层到页面上(composite layers--图层重组)
- 元素位置移动变换时尽量使用css3的transform来代替top,left等的造作变换(transform)和透明度(opacity)的改变仅影响涂层的组合
- 使用opacity来代替visivility
(1).使用visibility不触发重排,但是依然重绘
(2).直接使用opacity即触发重绘,又触发重排(GPU底层设计如此!)
(3).opacity配合图层使用,既不触发重绘也不会触发重排
原因:透明度的改变,GPU在绘画时知识简单的降低之前已经画好的纹理的alpha值来表达效果,并不需要整体的重绘。不过这个前提是这个被修改的opacity本身必须是一个图层。 - 不要使用table布局
table-cell - 将多次改变样式属性的操作合并成一次操作
不要一条一条的修改DOM的样式,预先定义好class,然后修改DOM的className - 将DOM离线后在修改
由于display属性为none的元素不在渲染树中,对隐藏的元素操作不会英法其他元素的重排,如果要对一个元素经行复杂的操作时,可以先隐藏他,操作完成后在显示,这样旨在隐藏和显示触发两次重排。 - 利用文档碎片(documentFragment)------vue使用这种方法提升性能
- 要把获取某些dom节点的属性值放在一个循环李当作循环的变量
- 动画实现过程,启用GPU硬件加速:transform:tranlateZ(0)
- 为动画元素新建图层,提高动画元素的z-index