是什么导致重排(layout / reflow)?

原文:What forces layout / reflow
笔记:涂鸦码龙

注:本文只摘取了自己认为重要的知识点,并没有逐字逐句翻译

当在 JavaScript 中调用(requested/called)以下所有属性或方法时,浏览器将会同步地计算样式和布局。重排(也有叫 reflow 或 layout thrashing 的),通常是性能瓶颈。

元素

盒子计算

  • elem.offsetLeft, elem.offsetTop, elem.offsetWidth, elem.offsetHeight, elem.offsetParent
  • elem.clientLeft, elem.clientTop, elem.clientWidth, elem.clientHeight
  • elem.getClientRects(), elem.getBoundingClientRect()

滚动相关

  • elem.scrollBy(), elem.scrollTo()
  • elem.scrollIntoView(), elem.scrollIntoViewIfNeeded()
  • elem.scrollWidth, elem.scrollHeight
  • elem.scrollLeft, elem.scrollTop,设置它们的值,同样会影响

获得焦点

还有…

  • elem.computedRole, elem.computedName
  • elem.innerText(源码

getComputedStyle

window.getComputedStyle() 通常会引起样式重新计算(源码

如果以下任何一种情况存在,window.getComputedStyle() 将会引起重排:

  1. 元素在 shadow tree 中
  2. 使用了 media queries (viewport相关的一种),特别是以下某一属性:(源码
    • min-width, min-height, max-width, max-height, width, height
    • aspect-ratio, min-aspect-ratio, max-aspect-ratio
    • device-pixel-ratio, resolution, orientation
  3. 获取以下的某一种属性:(源码
    • height, width
    • top, right, bottom, left
    • margin [-top, -right, -bottom, -left, 或简写] ,仅当 margin 是固定值。
    • padding [-top, -right, -bottom, -left, 或简写] ,仅当 padding 是固定值。
    • transform, transform-origin, perspective-origin
    • translate, rotate, scale
    • webkit-filter, backdrop-filter
    • motion-path, motion-offset, motion-rotation
    • x, y, rx, ry

window

  • window.scrollX, window.scrollY
  • window.innerHeight, window.innerWidth
  • window.getMatchedCSSRules() 仅重新计算样式

表单

  • inputElem.focus()
  • inputElem.select(), textareaElem.select()(源码

鼠标事件

  • mouseEvt.layerX, mouseEvt.layerY, mouseEvt.offsetX, mouseEvt.offsetY(源码

document

  • doc.scrollingElement 仅重新计算样式

Range

  • range.getClientRects(), range.getBoundingClientRect()

SVG

相当多;没有详尽的清单,但是 Tony Gentilcore’s 2011 Layout Triggering List 指出了一些。

contenteditable

数不胜数,…包含复制图片到剪切板(源码

附录

  • Reflow 仅在文档流已经改变,设定无效的样式或布局时,带来一定消耗。通常情况下,是由于 DOM 已经改变(class 名已修改,节点已新增/已移除,甚至添加一个伪类,像 :focus)。
  • 如果引起重排,样式首先必须重新计算。因此重排会触发两种操作。它的消耗非常依赖于内容/形势,但通常两种操作成本相似。
  • 我们该如何避免呢?长话短说:
    • for 循环里触发重排 & 改变 DOM 性能最低,尽量避免。
    • 使用 DevTools Timeline 看看问题在哪。
    • 合并读写 DOM 操作(通过 [FastDOM])(https://github.com/wilsonpage/fastdom) 或 虚拟 DOM 实现)

啃 Chromium 源码:

CSS Triggers

CSS Triggers 是非常棒的参考资源。设置/改变给出的 CSS 值,在浏览器的生命周期会出现什么结果,会触发哪些操作都有展示。

更多资料