-
Notifications
You must be signed in to change notification settings - Fork 12
Open
Description
什么导致强制布局/重排
原文链接
英文原文:What forces layout / reflow
以下所有属性或方法,当在 JS 中读写或调用,都将触发浏览器同步计算样式或布局。也被叫做重排或布局抖动,这通常是页面性能瓶颈。
元素
盒模型
elem.offsetLeft,elem.offsetTop,elem.offsetWidth,elem.offsetHeight,elem.offsetParentelem.clientLeft,elem.clientTop,elem.clientWidth,elem.clientHeightelem.getClientRects(),elem.getBoundingClientRect()
滚动
elem.scrollBy(),elem.scrollTo()elem.scrollIntoView(),elem.scrollIntoViewIfNeeded()elem.scrollWidth,elem.scrollHeightelem.scrollLeft,elem.scrollTop
聚焦
elem.focus()会造成两次强制布局 (source&l=2923)
其他
elem.computedRole,elem.computedNameelem.innerText(source&l=3440))
getComputedStyle
window.getComputedStyle() 典型的会造成强制计算样式
window.getComputedStyle() 以下情况将会导致强制布局:
- 该元素是影子树(shadow tree)
- 媒体查询(视口相关),尤其是以下情形 : (source)
min-width,min-height,max-width,max-height,width,heightaspect-ratio,min-aspect-ratio,max-aspect-ratiodevice-pixel-ratio,resolution,orientation,min-device-pixel-ratio,max-device-pixel-ratio
- 读取以下属性 : (source)
height,widthtop,right,bottom,leftmargin[-top,-right,-bottom,-left, 或简写] 仅当 margin 是固定值.padding[-top,-right,-bottom,-left,或简写] 仅当 padding 是固定值.transform,transform-origin,perspective-origintranslate,rotate,scalegrid,grid-template,grid-template-columns,grid-template-rowsperspective-origin- 以下这些貌似没影响了(自2018.02):
motion-path,motion-offset,motion-rotation,x,y,rx,ry
window
window.scrollX,window.scrollYwindow.innerHeight,window.innerWidthwindow.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
- 太多了,无法弄哦详尽的列表 , Tony Gentilcore's 2011 Layout Triggering List 列出了一些。
内容可编辑 contenteditable
- 太多了,包括复制图片到剪贴板 (source)
附录 *Appendix
- 重排的开销产生是由于文档改变导致先前的样式布局无效,典型的像 DOM 元素样式修改、添加删除,甚至添加一些伪类(如 :focus )都会导致重排。
- 在强制布局之前先要执行样式计算,所有强制布局需要执行渲染管道中的两者。样式计算和布局的开销取决于内容的复杂情况,一般两者的开销相比是差不多的。
- 最佳实践。关于更多强制布局的各方面细节可以在文末文章引用部分查看。以下是简要概括:
- 避免在 for 循环中同时进行会引发布局的操作和操作 DOM。
- 利用 Chrome 的 Performance 功能查看哪些代码或第三方库引发了强制布局。
- 批量读写DOM(通过 FastDOM or a virtual DOM)。在每帧的开始读取会引发布局属性的值(例如会频繁多次调用的 requestAnimationFrame,scroll 回调函数等之前就读取好),当这些属性的值在最终布局后依然不变。(举个例子:当父元素宽度为100px,for 循环修改所有的子元素宽度为父元素的一半,由于在修改每个子元素的过程中,仍然取父元素的一半 50px,这个时候就应该在 for 之前读取。如果在 for 循环之中读取,由于你修改了子元素的属性,浏览器无法确定对父元素有没有影响,只能强制重排一次来确定(仍然是 50px )。特别是在循环次数比较多的场景,性能会极差。)
跨浏览器 Cross-browser
- 以上数据信息取自 Blink 引擎源代码,所以对大多数浏览器都是真实的。
- 2011 WebKit 情况和以上差不多。Tony Gentilcore's Layout Triggering List
- 现代 WebKit 引擎强制布局行为基本一致。
updateLayoutIgnorePendingStylesheets- GitHub search - WebKit/WebKit - Gecko 引擎重排操作似乎通过 FrameNeedsReflow。
FrameNeedsReflow- mozilla-central search - 没有IE具体的数据,现代浏览器行为基本遵行规范,行为大体还是一致的,只是在优化方面稍有不同。
浏览 Chromium 源代码
- 强制重排(样式计算):
UpdateStyleAndLayoutIgnorePendingStylesheets- Chromium Code Search - 强制样式计算:
UpdateStyleAndLayoutTreeIgnorePendingStylesheets- Chromium Code Search
CSS Triggers
CSS Triggers 是一个重要的资源网站,描述了哪些样式改变会引发渲染管道哪些周期会被执行。以上讲的 JS 操作导致强制重排都会引发渲染管道中的布局、绘制、合成三者同步执行。
更多有关强制布局的文章 More on forced layout
- Avoiding layout thrashing — Web Fundamentals
- Fixing Layout thrashing in the real world | Matt Andrews
- Timeline demo: Diagnosing forced synchronous layouts - Google Chrome
- Preventing 'layout thrashing' | Wilson Page
- wilsonpage/fastdom
- Rendering: repaint, reflow/relayout, restyle / Stoyan
- We spent a week making Trello boards load extremely fast. Here’s how we did it. - Fog Creek Blog
- Minimizing browser reflow | PageSpeed Insights | Google Developers
- Optimizing Web Content in UIWebViews and Websites on iOS
- Accelerated Rendering in Chrome
- web performance for the curious
- Jank Free
2018.02 修改:代码搜索链接,部分相关元素属性。
dbssAlan
Metadata
Metadata
Assignees
Labels
No labels
