重排和重绘

参考资料 https://juejin.im/post/5c15f797f265da61141c7f86

接上浏览器渲染过程

经过对浏览器渲染过程的了解,最后两步就是渲染,也就是在这个阶段出现了重排重绘,也同时是最耗时的阶段。(意思就是说在第一次加载页面的时候,就会出现重排重绘)。

重排(回流)

当DOM的变化影响到了元素的几何信息,浏览器需要重新计算元素的宽高信息和位置信息。这个过程叫重排。

触发的条件

1.添加或者删除可见的DOM元素;

2.元素尺寸改变——边距、填充、边框、宽度和高度

3.内容变化,比如用户在input框中输入文字

4.浏览器窗口尺寸改变——resize事件发生时

5.计算 offsetWidth 和 offsetHeight 属性

6.设置 style 属性的值

WX20190111-234924@2x

重绘

当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,叫做重绘。

常见的引起重绘的属性:

WX20190112-135121@2x

浏览器的渲染队列

1
2
3
4
div.style.left = '10px';
div.style.top = '10px';
div.style.width = '20px';
div.style.height = '20px';

按照之上的来说,这段代码应该重排+重绘4次,但是浏览器的渲染队列会把所有会引起重排、重绘的操作放入渲染队列队列,直到达到一定数量,或者一定时间,才进行一次重排和重绘。让多次的重排和重绘合并为一次。

那么怎样会阻止多次的重排和重绘合并成一次呢?

1
2
3
4
5
6
7
8
div.style.left = '10px';
console.log(div.offsetLeft);
div.style.top = '10px';
console.log(div.offsetTop);
div.style.width = '20px';
console.log(div.offsetWidth);
div.style.height = '20px';
console.log(div.offsetHeight);

这段代码会触发4次重排+重绘,因为为了获取精确的值,浏览器会立即重排+重绘,才能获取到。

强制刷新队列的style样式请求

  1. offsetTop, offsetLeft, offsetWidth, offsetHeight
  2. scrollTop, scrollLeft, scrollWidth, scrollHeight
  3. clientTop, clientLeft, clientWidth, clientHeight
  4. getComputedStyle(), 或者 IE的 currentStyle

每一次的使用这些style的样式请求,要注意上下文,否则容易引起重排+重绘

优化

1.分离读写

1
2
3
4
5
6
7
8
div.style.left = '10px';
div.style.top = '10px';
div.style.width = '20px';
div.style.height = '20px';
console.log(div.offsetLeft);
console.log(div.offsetTop);
console.log(div.offsetWidth);
console.log(div.offsetHeight);

这样的话只会引起一次重绘+重排

2.添加class或者id,或者一次性的改变样式

1
2
3
4
5
el.className += " theclassname";
//或者
var left = 10;
var top = 10;
el.style.cssText += "; left: " + left + "px; top: " + top + "px;";

3.缓存布局信息

1
2
3
4
5
6
7
8
9
// bad 强制刷新 触发两次重排
div.style.left = div.offsetLeft + 1 + 'px';
div.style.top = div.offsetTop + 1 + 'px';

// good 缓存布局信息 相当于读写分离
var curLeft = div.offsetLeft;
var curTop = div.offsetTop;
div.style.left = curLeft + 1 + 'px';
div.style.top = curTop + 1 + 'px';

我对第一段的理解就是先读div.offsetLeft的信息加1,赋值给div.style.left,然后因为又取了div.offsetTop导致要马上的重排+重绘,才可以获取到,然后加1,赋值给div.style.top,之后又一次重排+重绘。

而第二段,先读两个属性信息,之后设置left和top,都进入渲染队列,没有读操作,所以只会重排+重绘一次。

4.使用position,设置属性为absolute或fixed

position属性为absolute或fixed的元素,重排开销比较小,不用考虑它对其他元素的影响。(我认为是因为absolute和fixed都会使元素彻底脱离文档流,所以才影响比较小)。

总结

重排必定重绘,而重绘不一定重排。

在写这个时候感觉有点直接抄别人的了,没怎么查资料哈哈哈哈哈。