共计 2375 个字符,预计需要花费 6 分钟才能阅读完成。
Avoid Large, Complex Layouts and Layout Thrashing
布局是浏览器计算元素几何信息的中央:即元素在页面中的大小和地位。每个元素都将具备基于所应用的 CSS、元素的内容或父元素的显式或隐式大小信息。该过程在 Chrome、Opera、Safari 和 Internet Explorer 中称为布局 (Layout).
在 Firefox 中,它被称为回流 (reflow),但实际上过程是雷同的。
与款式计算相似,布局老本的间接关注点是:
- 须要布局的元素数量。
- 这些布局的复杂性。
简而言之:
- 布局通常限定于整个文档。
- DOM 元素的数量会影响性能;你应该尽可能防止触发布局。
- 评估布局模型性能;新的 Flexbox 通常比旧的 Flexbox 或基于浮动的布局模型更快。
- 防止强制同步布局和布局抖动;读取款式值而后进行款式更改。
Avoid layout wherever possible
当您更改款式时,浏览器会查看是否有任何更改须要计算布局,以及是否须要更新渲染树。更改“几何属性”,例如宽度、高度、左侧或顶部都须要执行布局过程。
.box {
width: 20px;
height: 20px;
}
/**
* Changing width and height
* triggers layout.
*/
.box--expanded {
width: 200px;
height: 350px;
}
布局简直总是作用于整个文档。如果您有很多元素,则须要很长时间能力弄清楚它们的地位和尺寸。
如果无奈防止布局,那么要害是再次应用 Chrome DevTools 来查看须要多长时间,并确定布局是否是造成瓶颈的起因。首先,关上 DevTools,转到 Timeline 选项卡,点击记录并与您的站点进行交互。当您进行录制时,您会看到您的网站体现的细分:
在上例中深入研究帧时,咱们看到在布局外部破费了超过 20 毫秒,当咱们有 16 毫秒在动画中在屏幕上显示帧时,这太高了。您还能够看到 DevTools 会告诉您树的大小(在本例中为 1,618 个元素),以及须要布局的节点数量。
Avoid forced synchronous layouts
将网页运送到屏幕具备以下程序:
首先运行 JavaScript,而后是款式计算,而后是布局。然而,能够应用 JavaScript 强制浏览器提前执行布局。它被称为强制同步布局。
首先要记住的是,当 JavaScript 运行时,前一帧中的所有旧布局值都是已知的,可供您查问。因而,例如,如果您想在帧的结尾写出元素的高度(让咱们称其为“框”),您能够编写如下代码:
// Schedule our function to run at the start of the frame.
requestAnimationFrame(logBoxHeight);
function logBoxHeight() {
// Gets the height of the box in pixels and logs it out.
console.log(box.offsetHeight);
}
如果你在询问高度之前扭转了盒子的款式,事件就会变得有问题:
function logBoxHeight() {box.classList.add('super-big');
// Gets the height of the box in pixels
// and logs it out.
console.log(box.offsetHeight);
}
当初,为了答复高度问题,浏览器必须先利用款式更改(因为增加了超大类),而后运行布局。只有这样,它能力返回正确的高度。这是不必要的并且可能是低廉的工作。
因而,您应该始终批量读取款式并首先执行(浏览器能够应用前一帧的布局值),而后执行任何写入:
正确实现上述性能将是:
function logBoxHeight() {
// Gets the height of the box in pixels
// and logs it out.
console.log(box.offsetHeight);
box.classList.add('super-big');
}
在大多数状况下,您不须要利用款式而后查问值;应用最初一帧的值就足够了。同步运行款式计算和布局并早于浏览器的预期是潜在的瓶颈,而不是您通常想要做的事件。
Avoid layout thrashing
有一种办法能够使强制同步布局变得更糟:疾速间断地进行大量布局。看看这段代码:
function resizeAllParagraphsToMatchBlockWidth() {
// Puts the browser into a read-write-read-write cycle.
for (var i = 0; i < paragraphs.length; i++) {paragraphs[i].style.width = box.offsetWidth + 'px';
}
}
此代码遍历一组段落并设置每个段落的宽度以匹配名为“box”的元素的宽度。它看起来有害,但问题是循环的每次迭代都会读取一个款式值(box.offsetWidth),而后立刻应用它来更新段落的宽度(paragraphs[i].style.width)。在循环的下一次迭代中,浏览器必须思考自上次申请 offsetWidth(在前一次迭代中)以来款式已更改的事实,因而它必须利用款式更改并运行布局。这将在每次迭代中产生!。
此示例的修复办法是再次读取而后写入值:
// Read.
var width = box.offsetWidth;
function resizeAllParagraphsToMatchBlockWidth() {for (var i = 0; i < paragraphs.length; i++) {
// Now write.
paragraphs[i].style.width = width + 'px';
}
}
更多 Jerry 的原创文章,尽在:” 汪子熙 ”: