周分享

回流和重绘——周分享

2020-03-21  本文已影响0人  橙汁坤

浏览器的回流与重绘 (Reflow & Repaint)

image.png image.png

一句话:回流必将引起重绘,重绘不一定会引起回流。就比如改变个div的背景颜色并不会触发回流,可是改变了浏览器窗口大小或者改变了这个div的宽度或位置就触发了回流。


回流

通过构造渲染树(Render Tree),我们将可见DOM节点以及它对应的样式结合起来,可是我们还需要计算它们在设备视口内的确切位置和大小,这个计算的阶段就是回流

重绘

通过构造渲染树(Render Tree)和回流阶段,我们知道了哪些节点是可见的,以及可见节点的样式和具体的几何信息(位置、大小),那么我们就可以将渲染树的每个节点都转换为屏幕上的实际像素,这个阶段就叫做重绘节点。

当代浏览器的优化
clientWidth、clientHeight、clientTop、clientLeft
offsetWidth、offsetHeight、offsetTop、offsetLeft
scrollWidth、scrollHeight、scrollTop、scrollLeft
width、height
getComputedStyle()
getBoundingClientRect()

正常浏览器会维护一个队列,把所有引起回流和重绘的操作放入队列中,如果队列中的任务数量或者时间间隔达到一个阈值的,浏览器就会将队列清空,进行一次批处理,这样可以把多次回流和重绘变成一次。
当你访问上述的属性或方法时,队列中可能会有影响到这些属性或方法返回值的操作,浏览器便会强行清空队列,确保你拿到的值是最精确的。

const el = document.getElementById('element');
el.style.padding = '2px';
el.style.borderLeft = '2px';
el.style.width = '30px';
·········

有多个样式属性被修改了,每一个都会影响元素的几何结构,引起回流、有其他代码访问了布局信息(上文中的会触发回流的布局信息),那么就会导致多次重绘。因此,可以通过添加整个CSS的类来合并所有的改变然后依次处理。


const el = document.getElementById('element');
el.className += ' active';

<style>
.active{
    padding: 2px;
    borderLeft: 2px;
    width: 30px;
}
</style>
const el = document.getElementById('test');
function test() {
    for (let i = 0; i < 100; i++) {
        i.style.width = `${box.offsetWidth}px`;
    }
}

这段代码看上去是没有什么问题,可是其实会造成很大的性能问题。立即回流是同步的在每次循环的时候,都读取了box的一个offsetWidth属性值,然后利用它来更新标签的width属性。这就导致了每一次循环的时候,都会强制浏览器刷新队列。才能响应本次循环的样式读取操作。

const width = box.offsetWidth;
function test() {
    for (let i = 0; i < 100; i++) {
        i.style.width =`${width}px';
    }
}

可以定义一个变量来缓存box的offsetWidth属性值,避免循环中回流。

总结一下:
会引起元素位置变化的就会回流(Reflow),如窗口大小改变、字体大小改变、以及元素位置改变,都会引起周围的元素改变他们以前的位置;
不会引起位置变化的,只是在以前的位置进行改变背景颜色等,只会重绘(Repaint);

上一篇 下一篇

猜你喜欢

热点阅读