【问题标题】:Avoiding HTML document reflows避免 HTML 文档重排
【发布时间】:2013-11-17 21:50:39
【问题描述】:

我有几百个这样的“行”元素:

<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 位于绝对定位的祖先中 - 不应该只重排绝对定位的元素吗?

编辑:

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

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

把代码改成这样就解决了问题:

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

【问题讨论】:

  • 一个建议。如果您可以在开始时将您的 div 行设为静态并获取它的 innerHieght,然后将其更改为绝对。或者添加和删除类,您可以计算节点的总高度。
  • 为什么用div来模拟表格而不是用表格?

标签: javascript performance dom reflow


【解决方案1】:

这是一个有点老的问题,但我在研究这个问题时偶然发现了它,所以我想我会为其他人分享我在研究过程中发现的东西。

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

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

【讨论】:

    【解决方案2】:

    clientHeight 属性不会强制重排,至少它本身不会。触发回流需要两件事:

    1. 弄脏当前布局(设置布局属性,如宽度或高度)
    2. 查询布局属性(例如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(); 
    });
    

    【讨论】:

    • 这是正确的。谢谢你。在我的循环中,我正在做:element.style.height = element.clientHeight。如果我先获取所有高度,然后将它们设置在另一个循环中,则没有不必要的回流。
    • 什么是div.getClientHeight()?你的意思是div.getBoundingClientRect()
    • @AlejandroIglesias 是自定义函数,缓存高度避免强制回流。
    【解决方案3】:

    只要 DOM 发生变化,重排就会排队,但仅在以下任一情况下执行:

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

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

    所以,为了避免回流,你必须遵守以下规则

    • 在更改 DOM 时不要查询它,并且

    • 当你想查询 DOM 时不要更改它

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

    【讨论】:

    • 不错的答案投票。你能提供一些javascript例子吗?初学者请。
    猜你喜欢
    • 1970-01-01
    • 2021-08-01
    • 2012-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-20
    • 1970-01-01
    • 2019-08-01
    相关资源
    最近更新 更多