在DOM环境中,何时会发生回流?

53

什么样的活动会触发DOM重排?

似乎有不同的观点。根据http://www.nczonline.net/blog/2009/02/03/speed-up-your-javascript-part-4/,会在以下情况下发生:

  • 添加或删除DOM节点时。
  • 动态应用样式(例如element.style.width="10px")。
  • 检索必须计算的测量值,例如访问offsetWidth、clientHeight或任何计算的CSS值(通过DOM兼容的浏览器中的getComputedStyle()或IE中的currentStyle)。

然而,根据http://dev.opera.com/articles/view/efficient-javascript/?page=3,仅当已经排队了回流操作时,才会在获取测量值时触发重排。

还有其他想法吗?


不同的浏览器表现不同。 - some
10
除非它们的行为相同。 ;) - coderjoe
请查看Paul Irish关于避免回流的演讲:回流是由高度、宽度、offsetWidth等变化引起的。绝对定位不会触发回流 - ruhong
3个回答

49

这两篇文章都是正确的。

可以合理地假设,当你正在执行可能需要计算DOM元素尺寸的操作时,你将触发回流。

此外,据我所知,这两篇文章表达的意思都一样。

第一篇文章说,当:

当您检索必须计算的测量值(例如访问offsetWidth、clientHeight或任何计算出的CSS值(通过DOM兼容浏览器中的getComputedStyle()或IE中的currentStyle)时, DOM更改排队等待进行。

第二篇文章则陈述道:

如前所述,浏览器可以为您缓存多个更改,并仅在这些更改全部完成后才重新布局。但是,请注意,获取元素的尺寸将强制它重新布局,以便测量结果准确。更改可能不可见重绘,但是重新布局本身仍然必须在后台发生。

当使用像offsetWidth这样的属性进行测量,或者使用像getComputedStyle这样的方法时,就会产生这种效果。即使未使用这些数字,但只要在浏览器仍在缓存更改时使用其中任何一个,就足以触发隐藏的回流。如果反复进行这些测量,则应考虑仅进行一次测量,并存储结果,然后稍后可以使用该结果。

我认为这表示了他们早期所说的同样的事情。 Opera将尽最大努力为您缓存值并避免重新布局,但是您不应该依赖其能力。

在所有情况下,当他们说这三种类型的交互都可能导致回流时,就相信他们所说的吧。

干杯。


有没有办法强制重新绘制(除了回流)?为了以小的增量渲染大页面,从而提高最终用户感知的渲染速度。 - Jean Vincent
@coderjoe,“对元素进行测量将强制其重新流动”,为什么它们不被缓存在浏览器中?如果我立即连续调用getComputedStyle 3次,会发生什么!我会有3个重新流动吗! - faressoft
@faressoft 你误解了。重新排版只会在页面上的某些内容发生变化后才会发生。如果在调用之间没有对DOM进行任何更改,则仅第一个调用(可能)会导致重新排版,假设之前已经进行了更改。(嗯,有可能我不确定运行动画/过渡的效果...即使JS正在运行用户代码,它们也可能触发重新排版...我猜测不是这样,但如果它们确实如此,那么每次调用getComputedStyle()时都可能会导致重新排版)。 - Doin

4
请查看《理解Internet Explorer渲染行为》中的“通过属性读取访问触发渲染”部分,其中在IE中以下代码将导致渲染活动。请注意HTML标签的保留。
function askforHeight () {
  $("#lower").height();  
}

1
document.body.style.display = 'none';
document.body.style.display = 'block';

这通常可以解决那些难以理解的布局错误。


我遇到了一个IE6的bug,它会在错误的位置显示swf。通过设置swfObj.style.display = "block"来解决问题。 - aztack
32
哇,你们还需要支持IE6?坚强点,战士。 - I.devries

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接