首页 文章

避免HTML文档重排

提问于
浏览
5

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

<div class='row'>
  <div class='cell'></div>
  <div class='cell'></div>
  <div class='cell'></div>
</div>

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

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

Layout tree size  5901
Layout scope      Whole document

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

Edit:

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

rows.each(function(){
  $(this).css('height', this.clientHeight);
});

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

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

3 回答

  • 6

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

    • 脏了当前布局(设置宽度或高度等布局属性)

    • 查询布局属性(例如clientHeight)

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

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

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

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

    forEachDiv(function(div) {
      div.getClientHeight = function(){
        return div.cachedClientHeight = div.cachedClientHeight || div.clientHeight;
      }
    });
    

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

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

    // cache the client height for all divs now, to avoid reflows later
    forEachDiv(function(div) {
      div.getClientHeight(); 
    });
    
  • 23

    只要DOM发生变化,Reflow就会排队,但只有在以下情况之一时执行:

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

    • 查询必须呈现的计算值时,如 clientHeight .

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

    • 在更改DOM时不要查询DOM

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

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

  • 0

    这是一个古老的问题,但我在研究这个问题时偶然发现了它,所以我想我会分享我在研究其他人时发现的东西 .

    有一个非常好的库可以帮助您避免强制回流,尤其是在较大的应用程序上:https://github.com/wilsonpage/fastdom .

    该库的想法是将读取和写入分组到不同的阶段 .

相关问题