Open lingxiao-Zhu opened 3 years ago
参考谷歌开发者文档,通过自己的语言重新描述。
浏览器的一帧主要做了这件事情: 重排其实就是图中的第三步 Layout,Layout 是浏览器计算各元素几何信息的过程:元素的大小以及在页面中的位置。 根据所用的 CSS、元素的内容或父级元素,每个元素都将有显式或隐含的大小信息。
记住这几个阶段很重要
Layout 几乎总是作用到整个文档。 如果有大量元素,将需要很长时间来算出所有元素的位置和尺寸。
JavaScript 阶段强制浏览器提前执行 Layout。这被称为强制同步布局。 // 将JS函数放到一帧的最开始运行 requestAnimationFrame(logBoxHeight);
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属性,将元素提为单独图层,启动硬件加速,不会影响到其他节点。
什么是重排
浏览器的一帧主要做了这件事情: 重排其实就是图中的第三步 Layout,Layout 是浏览器计算各元素几何信息的过程:元素的大小以及在页面中的位置。 根据所用的 CSS、元素的内容或父级元素,每个元素都将有显式或隐含的大小信息。
为什么要避免重排
Layout 几乎总是作用到整个文档。 如果有大量元素,将需要很长时间来算出所有元素的位置和尺寸。
常见引起重排的问题
强制同步布局
function logBoxHeight() { console.log(box.offsetHeight); }
现在,为了回答高度问题,浏览器必须先应用样式更改(由于增加了 super-big 类)Style,然后运行 Layout,这时它才能返回正确的高度。这是不必要的,把一帧的时间拉长了,可能导致掉帧卡顿。
正确的方式应该是:
大部分情况下,并不需要应用样式然后查询值;使用上一帧的值就足够了。
如何避免重排
样式集中改变
批量的修改CSS样式,因为通过设置style属性改变结点样式的话,每一次设置都会触发一次reflow,所以最好是使用class属性
读写分离
对元素的修改,先统一取值,再统一赋值
脱离文档流
使用绝对定位会使的该元素单独成为渲染树中 body 的一个子元素,重排开销比较小,不会对其它节点造成太多影响。当你在这些节点上放置这个元素时,一些其它在这个区域内的节点可能需要重绘,但是不需要重排。
硬件加速
通过设置will-change、translate等CSS属性,将元素提为单独图层,启动硬件加速,不会影响到其他节点。