lingxiao-Zhu / blog

总结积累,读书笔记
3 stars 0 forks source link

什么是重排? #18

Open lingxiao-Zhu opened 3 years ago

lingxiao-Zhu commented 3 years ago

参考谷歌开发者文档,通过自己的语言重新描述。

什么是重排

浏览器的一帧主要做了这件事情: image 重排其实就是图中的第三步 LayoutLayout 是浏览器计算各元素几何信息的过程:元素的大小以及在页面中的位置。 根据所用的 CSS、元素的内容或父级元素,每个元素都将有显式或隐含的大小信息。

记住这几个阶段很重要

为什么要避免重排

Layout 几乎总是作用到整个文档。 如果有大量元素,将需要很长时间来算出所有元素的位置和尺寸。

常见引起重排的问题

强制同步布局

JavaScript 阶段强制浏览器提前执行 Layout。这被称为强制同步布局


// 将JS函数放到一帧的最开始运行
requestAnimationFrame(logBoxHeight);

function logBoxHeight() { console.log(box.offsetHeight); }

在示例中,目前正在 **JavaScript** 阶段执行JS,这样写没什么问题,不会引起重排,因为来自上一帧的所有旧布局值是已知的。

现在我们来改下logBoxHeight这个函数
```javascript
function logBoxHeight() {
  box.classList.add('super-big');
  // 输出元素的offsetHeight之前,为元素添加了新的类
  console.log(box.offsetHeight);
}

现在,为了回答高度问题,浏览器必须先应用样式更改(由于增加了 super-big 类)Style,然后运行 Layout,这时它才能返回正确的高度。这是不必要的,把一帧的时间拉长了,可能导致掉帧卡顿

正确的方式应该是:

function logBoxHeight() {
  // 先输出上一帧的offsetHeight
  console.log(box.offsetHeight);
  // 再添加新的类,就不会出发强制同步布局了
  box.classList.add('super-big');
}

大部分情况下,并不需要应用样式然后查询值;使用上一帧的值就足够了。

如何避免重排

样式集中改变

批量的修改CSS样式,因为通过设置style属性改变结点样式的话,每一次设置都会触发一次reflow,所以最好是使用class属性

// bad
var left = 10;
var top = 10;
el.style.left = left + "px";
el.style.top = top + "px";

// 当top和left的值是动态计算而成时...
// better 
el.style.cssText += "; left: " + left + "px; top: " + top + "px;";

// better
el.className += " className";

读写分离

对元素的修改,先统一取值,再统一赋值

// bad 强制刷新 触发四次重排+重绘
div.style.left = div.offsetLeft + 1 + 'px';
div.style.top = div.offsetTop + 1 + 'px';
div.style.right = div.offsetRight + 1 + 'px';
div.style.bottom = div.offsetBottom + 1 + 'px';

// good 缓存布局信息 相当于读写分离 触发一次重排+重绘
var curLeft = div.offsetLeft;
var curTop = div.offsetTop;
var curRight = div.offsetRight;
var curBottom = div.offsetBottom;

div.style.left = curLeft + 1 + 'px';
div.style.top = curTop + 1 + 'px';
div.style.right = curRight + 1 + 'px';
div.style.bottom = curBottom + 1 + 'px';

脱离文档流

使用绝对定位会使的该元素单独成为渲染树中 body 的一个子元素,重排开销比较小,不会对其它节点造成太多影响。当你在这些节点上放置这个元素时,一些其它在这个区域内的节点可能需要重绘,但是不需要重排。

硬件加速

通过设置will-change、translate等CSS属性,将元素提为单独图层,启动硬件加速,不会影响到其他节点。