1. 回流
当我们对DOM的修改引发了DOM几何尺寸的变化(比如修改元素的宽、高或隐藏元素等)时,浏览器需要重新计算元素的几何属性(其他元素的几何属性和位置也会因此受到影响),然后再将计算的结果绘制出来,这个过程叫做回流(重排)。
2. 重绘
当我们对DOM的修改导致了样式的变化、却并未影响其几何属性(比如只修改了颜色或背景色)时,浏览器不需要重新计算元素的几何属性,直接为该元素绘制新的样式(跳过了回流环节),这个过程叫做重绘。因此,重绘不一定导致回流,回流一定会导致重绘。
3. 触发举例
1)改变DOM元素的几何属性(width、height、padding、margin、left、right 等)。当一个DOM元素的几何属性发生变化时,所有和它相关的节点(比如父子节点、兄弟节点等)的几何属性都需要进行重新计算,它会带来巨大的计算量;
2)改变DOM树的结构:节点的增删、移动等操作;
3)获取一些特定的属性的值:offsetTop、offsetLeft、offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight。这些值有一个共性,就是需要通过即时计算得到,因此浏览器为了获取这些值,也会进行回流。
4、优化触发举例
1)多次计算得到一个元素的布局。
const el = document.getElementById('el'); //获取元素
for(let i = 0; i < 10; i ++) {
// 每次循环都要获取多次导致回流的值
el.style.top = el.offsetTop + 10 + 'px';
el.style.left = el.offsetLeft + 10 + 'px';
}
优化:
const el = document.getElementById('el'); //获取元素
let oT = el.offsetTop;
let oL = el.offsetLeft;
for(let i = 0; i < 10; i ++) {
oT += 10;
oL += 10;
}
el.style.top = oT + 'px';
el.style.left = oL + 'px';
2)尽量避免样式逐条改变:
const container = document.getElementById('container');
container.style.width = '100px';
container.style.heigt = '100px';
container.style.border = '1px solid red';
container.style.color = 'blue';
优化:
.change-style {
width: 100px;
height: 100px;
border: 1px solid red;
color: blue;
}
const container = document.getElementById('container');
container.classList.add('change-style');
3)DOM离线化:当进行很少的DOM操作时优越性不太明显,但是当操作频繁这样就会非常值得
const container = document.getElementById('container');
container.style.width = '100px';
container.style.heigt = '100px';
优化:
const container = document.getElementById('container');
container.style.display = 'none';
container.style.width = '100px';
container.style.heigt = '100px';
container.style.display = 'block';
4)浏览器缓存队列: flush 队列。这种机制不是每个浏览器都有。
浏览器的flush队列会把我们要触发的回流与重绘任务都塞进去,待到队列任务多起来、或者达到一定的时间间隔、或者需要执行的时候,再将这些任务一次性出队,因此这时候我们的回流与重绘只会触发一次。