Godiswill / blog

【大前端】分享记录

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

什么导致强制布局/重排

Godiswill opened this issue · comments

什么导致强制布局/重排

原文链接
英文原文:What forces layout / reflow

以下所有属性或方法,当在 JS 中读写或调用,都将触发浏览器同步计算样式或布局。也被叫做重排或布局抖动,这通常是页面性能瓶颈。

元素

盒模型
  • 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.focus() 会造成两次强制布局 (source&l=2923)
其他
  • elem.computedRole, elem.computedName
  • elem.innerText (source&l=3440))

getComputedStyle

window.getComputedStyle() 典型的会造成强制计算样式

window.getComputedStyle() 以下情况将会导致强制布局:

  1. 该元素是影子树(shadow tree)
  2. 媒体查询(视口相关),尤其是以下情形 : (source)
  • min-width, min-height, max-width, max-height, width, height
  • aspect-ratio, min-aspect-ratio, max-aspect-ratio
  • device-pixel-ratio, resolution, orientation , min-device-pixel-ratio, max-device-pixel-ratio
  1. 读取以下属性 : (source)
  • 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
  • grid, grid-template, grid-template-columns, grid-template-rows
  • perspective-origin
  • 以下这些貌似没影响了(自2018.02):
    motion-path, motion-offset, motion-rotation, x, y, rx, ry

window

  • window.scrollX, window.scrollY
  • window.innerHeight, window.innerWidth
  • window.getMatchedCSSRules() only forces style

Forms

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

Mouse events

  • mouseEvt.layerX, mouseEvt.layerY, mouseEvt.offsetX, mouseEvt.offsetY (source)

document

  • doc.scrollingElement 仅强制计算样式

Range

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

SVG

内容可编辑 contenteditable

  • 太多了,包括复制图片到剪贴板 (source)

附录 *Appendix

  • 重排的开销产生是由于文档改变导致先前的样式布局无效,典型的像 DOM 元素样式修改、添加删除,甚至添加一些伪类(如 :focus )都会导致重排。
  • 在强制布局之前先要执行样式计算,所有强制布局需要执行渲染管道中的两者。样式计算和布局的开销取决于内容的复杂情况,一般两者的开销相比是差不多的。
  • 最佳实践。关于更多强制布局的各方面细节可以在文末文章引用部分查看。以下是简要概括:
    1. 避免在 for 循环中同时进行会引发布局的操作和操作 DOM。
    2. 利用 Chrome 的 Performance 功能查看哪些代码或第三方库引发了强制布局。
    3. 批量读写DOM(通过 FastDOM or a virtual DOM)。在每帧的开始读取会引发布局属性的值(例如会频繁多次调用的 requestAnimationFrame,scroll 回调函数等之前就读取好),当这些属性的值在最终布局后依然不变。(举个例子:当父元素宽度为100px,for 循环修改所有的子元素宽度为父元素的一半,由于在修改每个子元素的过程中,仍然取父元素的一半 50px,这个时候就应该在 for 之前读取。如果在 for 循环之中读取,由于你修改了子元素的属性,浏览器无法确定对父元素有没有影响,只能强制重排一次来确定(仍然是 50px )。特别是在循环次数比较多的场景,性能会极差。)

(PS:Timeline 在最新的版本中已改成 Performance) Timeline trace of The Guardian. Outbrain is forcing layout repeatedly, probably in a loop.
跨浏览器 Cross-browser
浏览 Chromium 源代码

CSS Triggers

CSS Triggers 是一个重要的资源网站,描述了哪些样式改变会引发渲染管道哪些周期会被执行。以上讲的 JS 操作导致强制重排都会引发渲染管道中的布局、绘制、合成三者同步执行。

更多有关强制布局的文章 More on forced layout


2018.02 修改:代码搜索链接,部分相关元素属性。