前言
关于浏览器渲染我们需要知道:
- 浏览器使用流式布局模型
- 浏览器会把
HTML
解析成DOM
,把CSS
解析成CSSOM
,DOM
和CSSOM
合并就产生了Render Tree
。 - 有了
RenderTree
,我们就知道了所有节点的样式,然后计算他们在页面上的大小和位置,最后把节点绘制到页面上。 - 由于浏览器使用流式布局,对
Render Tree
的计算通常只需要比那里一次就可以完成,但table
及其内部元素除外,他们可能需要多次计算,通常要花3倍于同等元素的时间,这也是为什么要避免使用table
布局的原因之一
浏览器页面的呈现流程
- 浏览器把获取到的
HTML
代码解析称一个DOM
树,HTML
中每个tag
都是DOM
树中的一个节点,根节点就是我们常用的document
对象。DOM
树里包含了所有的HTML
标签,包括display:none
隐藏,还有用js动态添加的元素等。 - 浏览器把所有样式(用户定义的css和用户代理)解析称样式结构体,在解析的过程中会去掉浏览器不能识别的样式,比如IE会去掉-moz开头的样式
DOM Tree
和样式结构体组合后构建render tree
,render tree
能识别样式,render tree
中每个node都有自己的样式,而且render tree不包含隐藏的节点(比如display:none的节点,还有head节点)因为这些节点不会用于呈现,而且不会影响呈现的,所以就不会包含到render tree中
。注意visibility:hidden
隐藏的元素还是会包含到render tree
中的,因为这个样式会影响布局(layout),会占有空间。- 一旦
render tree
构建完毕后,浏览器就可以根据render tree
来绘制页面。
回流(Reflow)
什么是回流
当render tree
中的一部分因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流。每个页面至少需要一次回流,就是在页面第一次加载的时候。在回流时,浏览器会使渲染树中受到影响的部分失效,并重新构建这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程称为重绘。
会导致回流的操作
当页面布局和几何属性改变时就需要回流:
● 添加或者删除可见的DOM
元素
● 元素位置改变
● 元素尺寸改变——边距、填充、边框、宽度和高度
● 内容改变——比如文本改变或者图片大小改变而引起的计算值宽度和高度改变
● 页面渲染初始化
● 浏览器窗口尺寸改变——resize
事件发生时
重绘
什么是重绘
当render tree
中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color
。这种修改被称为重绘。需要注意的是回流一定会引起重绘,而重绘不一定会引起回流。
如何减少回流与重绘
减少回流、重绘其实就是需要减少对render tree
的操作(合并多次多DOM
和样式的修改),并减少对一些style
信息的请求,尽量利用好浏览器的优化策略。
Render Tree
的计算通常只需要遍历一次就可以完成,table
及其内部元素除外,这些需要多次计算,一般是3倍与同等元素的时间,所以我们要比避免使用table
布局- 尽可能在
DOM
树的最末端改变class。避免设置多层内联样式。将动画效果应用到position
属性为absolute
或fixed
的元素上,避免使用css表达式,如calc()
- 避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改为class属性。避免频繁操作DOM,创建一个
documentFragment
,在它上面应用所有的DOM操作,最后再把它添加到文档中。 - 可以先为元素设置
display:none
,操作结束后再把它显示出来。避免频繁的读取会引发回流/重绘,如果确实需要多次使用,就用一个变量缓存起来。
documentFragment
及最小文档片段。