reflow
去听了牛人 dbaron 的一个 Web Page Layout/Display in Mozilla 讲座(via)。讲的东西对我一个只会 HTML, CSS 和 JavaScript 的人来说很底层,所以效果也比较「和谐」,只是大致了解了 mozilla 的 CSS 渲染源码分布位置和渲染流程而已。
讲座提到了 reflow(如何翻译呢?又是一个问题)这个东东。之前对 reflow 有所闻,能经常从某些大牛的幻灯中提到,提高页面渲染的性能,需尽量避免 reflow. 那么 reflow 是什么东西呢?它又是如何影响页面性能的?事后去问了一下 dbaron(呵呵,我口语彻底不行,加上心理素质,最后是把问题写下来给他看),豁然开朗也。
在 CSS 规范中有一个渲染对象的概念,通常用一个盒子(box, rectangle)来表示。mozilla 通过一个叫 frame 的对象对盒子进行操作。frame 主要的动作有三个:
- 构造 frame, 以建立对象树(DOM 树)
- reflow, 以确定对象位置,或者是调用 mozilla 的 Layout(这里是指源码的实现)
- 绘制,以便对象能显示在屏幕上
总的来说,reflow 就是载入内容树(在 HTML 中就是 DOM 树)和创建或更新 frame 结构的响应的一种过程。
要提高页面性能,其实就是避免 reflow 的开销。那么,有哪些方面是需要 reflow 的呢?比如,未指定图片宽高的话,图片的载入会使页面 reflow, 因为要根据图片宽高来更新 frame。这里就有一个提高页面性能的小技巧:如果事先能够确定图片宽高的话,最好在 HTML 里写上。
在编写一些常见的动态效果时,一般使用 CSS 的 display
来切换可见性。很不幸,这也会产生 reflow. 把元素置为 display:none
,相当于把这个元素的 frame 销毁了,再置回非 none
时,需要重新构造 frame,这就产生了 reflow. 而另外一个切换可见性的属性 visibility
则不存在 reflow 问题,置为 visibility:hidden
的元素的 frame 并没有销毁,需要显示的时候其实就是一个绘制(上面提到的动作第三步)过程而已,没有 reflow,因此效率会更高。如果你看过一些 JavaScript 库/框架的源码,会发现它们大量使用 visibility
而不是 display
,道理应该如此。