重排、重绘及合成
一、重排
定义:部分渲染树(或者整个渲染树)需要重新分析并且节点尺⼨需要重新计算,表现为重新⽣成布局,重新排列元素。例如改变元素位置或大小等。
触发条件
- 添加、删除、更新DOM节点
- 通过display: none隐藏⼀个DOM节点
- 移动或者给⻚⾯中的DOM节点添加动画
- 添加⼀个样式表,调整样式属性
- ⽤户⾏为,例如调整窗⼝⼤⼩,改变字号,或者滚动。
- 页面渲染初始化(无法避免)
优化方案
- 尽量不要在布局信息改变时做查询(会导致渲染队列强制刷新)。
- 集中改变样式 。
// 判断是否是⿊⾊系样式
const theme = isDark ? 'dark' : 'light' 64
// 根据判断来设置不同的
class ele.setAttribute('className', theme)
- 避免使用table。
- 使用fragment元素(createDocumentFragment)
我们可以通过createDocumentFragment创建⼀个游离于DOM树之外的节点,然后在此节点上批量操作,最后插⼊DOM树中,因此只触发⼀次重排
var fragment = document.createDocumentFragment()
for (let i = 0; i<10; i++){
let node = document.createElement("p")
node.innerHTML = i
fragment.appendChild(node)
}
document.body.appendChild(fragment)
-
使用采用虚拟DOM的库,如Vue,React
-
提升为合成层
提升为合成层的优点:
-
合成层的位图,会交由 GPU 合成,⽐ CPU 处理要快
-
当需要 repaint 时,只需要 repaint 本身,不会影响到其他的层
-
对于 transform 和 opacity 效果,不会触发 layout 和 paint
-
提升合成层的最好⽅式是使⽤ CSS 的 will-change 属性(为web开发者提供了一种告知浏览器该元素会有哪些变化的方法,这样浏览器可以在元素属性真正发生变化之前提前做好对应的优化准备工作,这个最好用完后就释放):
#target {
will-change: transform;
}
二、重绘:
定义: 由于节点的⼏何属性发⽣改变或者由于样式发⽣改变,例如改变元素背景⾊时,屏幕上的部分内容需要更新,表现为某些元素的外观被改变 。
触发条件
- background属性(background,background-color,background-image,background-position,background-repeat,background-size)
- outline属性(outline,outline-color,outline-style)
- box-shadow属性
- border属性(border-style,border-radius)
- 通过visibility: hidden隐藏⼀个DOM节点
优化方案
- 合并多次操作
三、合成
定义: 更改一个既不要布局也不要绘制的属性,渲染引擎将跳过布局和绘制,只执行后续的合成操作,我们把这个过程叫做合成。比如我们使用了 CSS 的 transform
来实现动画效果,这可以避开重排和重绘阶段,直接在非主线程上执行合成动画操作。这样的效率是最高的,因为是在非主线程上合成,并没有占用主线程的资源,另外也避开了布局和绘制两个子阶段,所以相对于重绘和重排,合成能大大提升绘制效率。
触发条件
will-change
translate3d
、translateZ
- 整个图层的几何变换,透明度变换,阴影。
四、总结
『重绘』不⼀定会出现『重排』,『重排』必然会出现『重绘』。