避免HTML文档重排

dis*_*cer 7 javascript performance dom reflow

我有几百个"行"元素,如下所示:

<div class='row'>
  <div class='cell'></div>
  <div class='cell'></div>
  <div class='cell'></div>
</div>
Run Code Online (Sandbox Code Playgroud)

我们需要在已经在页面上呈现之后获取clientHeight.我知道"clientHeight"属性强制重排,这会影响我的表现,因为它们有很多.但是 - 它们已经被渲染,我知道它们的大小在它们渲染的时间和我查询它们的高度的时间之间没有变化.

在查询高度时,有没有办法告诉浏览器不要重排?此外 - webkit检查员说:

Layout tree size  5901
Layout scope      Whole document
Run Code Online (Sandbox Code Playgroud)

div是一个绝对定位的祖先 - 不应该只是绝对定位的元素被回流?

编辑:

所以提供的答案是正确的.我实际上弄脏了布局,因为我有这个循环:

rows.each(function(){
  $(this).css('height', this.clientHeight);
});
Run Code Online (Sandbox Code Playgroud)

将代码更改为此修复了问题:

var heights = rows.map(function(){
  return this.clientHeight;
});
rows.each(function(){
  $(this).css('height', heights.shift());
});
Run Code Online (Sandbox Code Playgroud)

sle*_*man 28

每当DOM更改时,Reflow都会排队,但只有在以下情况之一时执行:

  1. 没有更多的javascript要处理(脚本结束)或

  2. 当您查询必须呈现的计算值时,例如clientHeight.

因此,为了避免回流,您必须遵循以下规则

  • 在更改DOM时不要查询DOM

  • 如果要查询DOM,请不要更改DOM

实际上,这意味着在完成修改DOM之后,应该在脚本末尾对所有查询操作进行分组.这样做只会为数千个元素重排一次,而不是每个元素重复数千次.


Tib*_*bos 6

clientHeight属性不会强制重排,至少不会自行强制重排.你需要两件事来触发回流:

  1. 弄脏当前布局(设置宽度或高度等布局属性)
  2. 查询布局属性(例如clientHeight)

您可以轻松批量调用以设置宽度或高度,并且在JS上下文放弃控制之前不会发生重排.您可以轻松地批量查询布局属性,如果当前布局不脏,则不会发生重排.

连续执行1和2时会出现问题.强制重排是为了满足您的查询准确信息.

据我所知,你是正确的,有一个绝对定位的祖先应该限制回流在整个文件"蔓延"(绝对定位的祖先的父母将不会回流).绝对定位的祖先里面的所有物品仍然会回流!

至于你的问题的解决方案是的.设置一个缓存机制,像这样(伪代码):

forEachDiv(function(div) {
  div.getClientHeight = function(){
    return div.cachedClientHeight = div.cachedClientHeight || div.clientHeight;
  }
});
Run Code Online (Sandbox Code Playgroud)

然后您可以使用div.getClientHeight()而不是div.clientHeight多次,只有第一次使用才会触发重排(如果是脏的).

显然,与第一个建议保持一致,您也可以在一个批次(=一个回流)中人工查询clientHeight中的所有div,之后您就不再有问题了.

// cache the client height for all divs now, to avoid reflows later
forEachDiv(function(div) {
  div.getClientHeight(); 
});
Run Code Online (Sandbox Code Playgroud)