Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

什么导致强制布局/重排 #3

Open
Godiswill opened this issue Sep 1, 2019 · 0 comments
Open

什么导致强制布局/重排 #3

Godiswill opened this issue Sep 1, 2019 · 0 comments

Comments

@Godiswill
Copy link
Owner

Godiswill commented Sep 1, 2019

什么导致强制布局/重排

原文链接
英文原文: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 修改:代码搜索链接,部分相关元素属性。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant