避免复杂的layout

layout是浏览器计算元素的几何信息:元素在页面上的的大小和位置。

每个元素都有明确的亦或含蓄的大小信息,这些信息基于我们使用的css以及元素的内容被高和父亲元素。

这个过程在 Chrome, Opera, Safari, 和Internet Explorer中叫做Layout.在火狐浏览器中叫做Reflow。

  • Layout的范围是整个文档
  • DOM元素的数量将会影响表现性能:你应该尽可能的禁止触发layout
  • 估计layout模型的性能:新的FlexBox比原来的基于float的layout模型要快的多

影响layout性能的是:

  1. 需要layout的元素数量
  2. layout的复杂程度

尽可能避免使用layout

当你修改样式的时候,浏览器会检查你的修改是否会要求layout被计算,如果有的话讲更新render tree。

会触发layout的属性都是“几何的属性”,例如: widths, heights, left, or top 等

.box {
  width: 20px;
  height: 20px;
}

/**
 * Changing width and height
 * triggers layout.
 */
.box--expanded {
  width: 200px;
  height: 350px;
}

 

layout作用于整个文档,所以如果有许多的元素的话,将花费很长的时间来计算元素的位置和大小。

如果不可避免使用layout,那么使用Chrome开发者工具的timeline来追踪查看每个layout的耗费。

DevTools showing a long time in Layout

我们可以看见上面我们在layout上面花费了20ms多,如果我们在动画上花费了16ms,那么这个动画就耗费太多资源了。

你同样可以看见开发者工具总告诉我们树的大小(在上面的情况中有1618个元素),也告诉我们多少节点需要被layout。

Note

  • 想要一个确切的css属性清单确认哪些属性触发layout,paint和 dimensions ?点击这里:CSS Triggers.

用flexbox替代老的layout模型

网络有一系列的layout模型,一些的支持性相对于其他模型支持性更好。

旧的layout模型允许我们将元素相对定位,亦或绝对定位,亦或float布局在屏幕上。

下面的截图展示了一个layout(在1300个box上使用float布局)的耗费,这是一个手动的例子,因为现实的应用中我们会使用一系列的定位方式来定位元素。

Using floats as layout

如果我们使用FlexBox来定位元素,下面将展示不同:

Using flexbox as layout

现在我们在布局上节省了一些时间(例子中3.5msVS14ms),记住上面的对比是作用在相同的元素且产生相同的效果。

虽然很少的浏览器支持flex布局,但是为了很好的性能,你还是要进行尝试!

查看flexbox布局支持比float少的文档: less widely supported than floats

总而言之,不管你使用的浏览器是否支持flexBox,你都应该尽可能的避免触发layout.

 

避免强制执行layout

将帧运输到屏幕上的顺序是下面这样的:

Using flexbox as layout

先运行js,之后计算样式,然后layout。

但是,我们可以强迫浏览器在js之前执行layout。这被叫做强制执行layout。

 

首先要知道的是在所有旧的layout上面js可以访问之前帧的任何内容。

下例中,我们想在帧的开始书写一个元素(让我们把它叫做“盒子”)的高度,我们书写代码如下:

// 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);
}

 

如果我们在js获取盒子高度之前就改变了盒子的高度样式,那么会产生问题:

function logBoxHeight() {

  box.classList.add('super-big');

  // Gets the height of the box in pixels
  // and logs it out.
  console.log(box.offsetHeight);
}

 

现在,浏览器为了计算js中的高度问题,浏览器必须先运行样式的改变(因为代码中加入了super-class样式),然后运行layout。只有这样才能返回正确的高度。这是不必要且耗费巨大的工作。

因为你总是要先读取样式(样式信息保存在之前的帧的layout值中),然后再进行任何的书写操作:

正确的代码是这样的:

function logBoxHeight() {
  // Gets the height of the box in pixels
  // and logs it out.
  console.log(box.offsetHeight);

  box.classList.add('super-big');
}

 

在大多数情况下你不必要先应用样式然后计算值;使用最后一帧的值将变得绰绰有余。强制layout在js之前运行将会耗费巨大,且浏览器将会进入瓶颈,这是我们不想看到的。

避免layout thrashing

比上面强制执行layput更加糟糕的是:连续执行强制layout。

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的offWidth的值并且将其赋值给一个paragraph(paragraphs[i].style.width)。在洗一次循环的时候,浏览器会计算已经更改的布局,然后再进行layout,每一个循环都会这样的进行!

更改之后变得更加可度:

// Read.
var width = box.offsetWidth;

function resizeAllParagraphsToMatchBlockWidth() {
  for (var i = 0; i < paragraphs.length; i++) {
    // Now write.
    paragraphs[i].style.width = width + 'px';
  }
}

 

如果你想确保安全性,你可以在 FastDOM网站上检查。该网站好处。。。。你试过就知道了

posted @ 2016-05-04 19:54  RachelChen  阅读(543)  评论(0编辑  收藏  举报