什么是 reflow 和 repaint
浏览器为了重新渲染部分或整个页面,重新计算页面元素位置和几何结构(geometries)的进程叫做 reflow。
当确定了元素位置、大小以及其他属性,例如颜色、字体大小等都确定下来后,浏览器于是便把这些元素都按照各自的特性绘制了一遍,于是页面的内容出现了,这个过程称之为 repaint。
当修改一个元素的外观(例如 outline、visibility、background color 等)但并不影响到元素的布局时,就会发生 repaint。
repaint 是昂贵的,因为浏览器会确认在DOM树中所有其他元素的 visibility 属性。
reflow 更昂贵,因为某个节点reflow时会触发其子节点,甚至包括祖先节点(根据浏览器)和文件中位于该节点以下的其他节点 reflow。由于 reflow 是一种浏览器中的用户拦截(user-blocking)操作,所以了解如何减少 reflow 次数,及不同的文档属性(DOM 层级(DOM depth),CSS 效率,不用类型的 style 变化)对 reflow 次数的影响对开发者来说非常必要。
引发 reflow 的一些因素:
调整窗口大小(Resizing the window)
改变字体大小(Changing the font)
增加或者移除样式表(Adding or removing a stylesheet)
内容变化,比如用户在input框中输入文字(Content changes, such as a user typing text in an input box)
激活 CSS 伪类,比如 :hover (IE 中为兄弟结点伪类的激活)(Activation of CSS pseudo classes such as :hover (in IE the activation of the pseudo class of a sibling))
操作 class 属性(Manipulating the class attribute)
脚本操作 DOM(A script manipulating the DOM)
计算 offsetWidth 和 offsetHeight 属性(Calculating offsetWidth and offsetHeight)
设置 style 属性的值 (Setting a property of the style attribute)
未指定图片宽高,载入时会使页面reflow
对于减少 reflow 优化性能的建议:
-
如果想设定元素的样式,通过改变元素的 class 名 (尽可能在 DOM 树的最里层)(Change classes on the element you wish to style (as low in the dom tree as possible))
因为元素reflow时,会使所有子孙元素都reflow。
-
避免设置多项内联样式(Avoid setting multiple inline styles)
就像往页面添加元素时,把所有html代码组装成字符串后一次性添加至dom中一样,最好是把所有要修改的样式放在一个类名中,而不是把样式依次添加到元素的内联样式里,因为每次修改内联样式都会触发 reflow。
-
应用动画的元素,使用 position 属性的 fixed 值或 absolute 值(Apply animations to elements that are position fixed or absolute)
元素脱离正常文档流以后reflow 就不会对文档流内的元素造成影响
-
权衡平滑和速度(Trade smoothness for speed)
给元素添加动画时,以3个像素为移动单位可能比每次移动1个像素看起来更加平滑,因为每次移动都会触发reflow,过于频繁的reflow会占用更多CPU资源,可能导致动画看起来是卡顿的。
-
避免使用 table 布局或者将其 table-layout 设置为 fixed(Avoid tables for layout or set table-layout fixed)
在table中,后面添加的元素对其前面元素的布局会产生影响,例如:最后一个单元格的内容过多,使得整列宽度增加。而且对于table的一点点修改都可能造成 table 内所有元素的 reflow。将 table-layout 设置为 fixed 时水平布局仅取决于表格宽度、列宽度、表格边框宽度、单元格间距,而与单元格的内容无关。浏览器在接收到第一行后就可以显示表格,而不用等整个表格加载完并调整好才展示。固定布局算法比较快,但是不太灵活,而自动算法比较慢,不过更能反映传统的 HTML 表。
-
避免使用CSS表达式 (仅 IE 浏览器)(Avoid expressions in the CSS (IE only))
- 因为每次触发 reflow 都会重新计算表达式
这里介绍一款强大的性能分析工具 dynaTrace,借助该功能能够清晰的得到页面中的资源消耗情况。
参考: http://www.stubbornella.org/content/2009/03/27/reflows-repaints-css-performance-making-your-javascript-slow/