原文: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.focus() 可以引起两次重排(源码在此)
还有…
- elem.computedRole, elem.computedName
- elem.innerText(源码)
getComputedStyle
window.getComputedStyle()
通常会引起样式重新计算(源码)
如果以下任何一种情况存在,window.getComputedStyle()
将会引起重排:
- 元素在 shadow tree 中
- 使用了 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
- 获取以下的某一种属性:(源码)
- 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 源码:
- 触发重排(和重新计算样式):updateLayoutIgnorePendingStylesheets - Chromium Code Search
- 触发样式重算:updateLayoutTree - Chromium Code Search
CSS Triggers
CSS Triggers 是非常棒的参考资源。设置/改变给出的 CSS 值,在浏览器的生命周期会出现什么结果,会触发哪些操作都有展示。
更多资料
- 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