js - 重绘与回流

DOM树和样式结构体 (浏览器所能识别的所有样式) 构建组成渲染树 (render tree) 来完成绘制页面 

当渲染树的一部分发生改变, 若只引起页面的非布局外观 (如背景等) 发生改变时, 那这就是一次页面重绘(repaint)

若引起页面的布局发生改变, 那这就是一次页面回流 (reflow), 同时页面外观也发生改变, 意味着必然伴随重绘

 

  • 回流

添加/删除元素
display: none;
定位, 浮动, 边距等改变位置
改变盒模型
改变文字大小, 粗细, 位置, 间隔, 行高, 超出容器处理方式等
改变浏览器大小
激活伪类 (:hover)
内容变化 (input等输入文字)

 

  • 重绘

改变 visiblility, z-index, 轮廓, 颜色, 背景, 阴影等

 

回流的代价远比重绘昂贵, 很大程度影响着页面性能, 减缓JavaScript
而这里要做的就是规避回流, 降低回流造成的影响, 降低回流需要的成本

 

  • 规避DOM的频繁访问

切换和弹窗, 实际中这样的操作不只是一次, 而这里要说的是其中的回流成本

如 $(button) -> $.show(dialog), 相当于每次操作都要先访问DOM的"button"和"dialog"

变量存储, 将频繁操作的元素作为变量

避免用类名或样式属性来作为条件判断

 

  • 规避频繁影响DOM

将多个元素打包再添加到DOM

加入DOM前, 先赋予属性内容等

将需要改变的多个样式封装到一个类里, 然后只要改变className
若样式的属性值是动态的, 可以用cssText

 

  • 减少对其它元素的影响

文档流中, 在其它元素后添加内容

动态改变位置或盒模型, 会影响其它元素的, 建议用定位处理

图片设置宽高, 避免页面加载后, 再绘制高度, 影响其它元素

 

  • 规避页面刷新或访问新页面

页面加载时, 浏览器会把所有引起回流的操作在构建渲染树前排入一个队列, 并在出队列时批量处理, 然后执行一次页面绘制, 使这过程只发生一次回流

问题不仅是绘制页面的, 还包括绘制页面前的高昂成本

更新局部内容, 替代刷新页面

同页面中加载数据并展示新内容, 替代在打开新页面

当要访问布局上的回流数据, 如窗口大小等, 样式中的盒模型, 偏移量等属性, 浏览器同样将这些回流操作提前处理一遍, 然后执行一次页面绘制, 伴随一次页面回流

 

  • 动画优化

浏览器会在主线程外为执行CSS3动画的节点创建一个图层, 并把节点移到图层上, 然后通过CPU或GPU将同一个动画的每个节点所创建的图层组合成一个图层添加到页面, 最后执行动画, 这过程把节点移到图层上时产生了一个回流, 这个回流让同一个动画的每个节点都消失

把图层添加到页面又产生了一个回流, 这个回流花费的时间基本决定了动画开始前的准备时间, 如果所花的时间较长, 就会看到这些节点消失的瞬间, 如果用CPU处理 (CPU处理图层不及GPU), 所花的时间会更长

可想可知, transform 和 opacity 的动画过程没有回流, 但动画前却是一场噩梦

 开启设备硬件加速渲染, 即强制使用GPU进行2D绘图

用 translateZ() 或 translate3d() 代替 translate() 从而提高CPU的处理减少动画开始前的准备时间, 且不会随着抗锯齿而导出突变

但依旧免不了回流所耗的时间, 而且过多 translateZ() 或 translate3d() 占用CPU使用率, 将导致CPU性能下降

 

牺牲平滑度换取速度

每次1px移动一个动画, 可能导致动画及随后的回流占用了很高的CPU使用率, 动画就会看上去是跳动的, 因为浏览器正在与更新回流做斗争

动画元素每次移动3px可能在非常快的机器上看起来平滑度低了, 但它不会导致在CPU较慢的机器和移动设备中抖动

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章