浏览器渲染过程
- 解析HTML,构建DOM树(这里遇到外链,此时会发起请求)
- 解析CSS,生成CSS规则树
- 合并DOM树和CSS规则,生成render树
- 布局render树(Layout/reflow),负责各元素尺寸、位置的计算
- 绘制render树(paint),绘制页面像素信息
- 浏览器会将各层的信息发送给GPU,GPU将各层合成(composite),显示在屏幕上
1. 构建DOM树
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="style.css" rel="stylesheet">
<title>Critical Path</title>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg"></div>
</body>
</html>
无论是DOM还是CSSOM,都是要经过Bytes → characters → tokens → nodes → object model这个过程。
DOM树构建过程:当前节点的所有子节点都构建好后才会去构建当前节点的下一个兄弟节点。
2. 构建CSSOM树
上述也提到了CSSOM的构建过程,也是树的结构,在最终计算各个节点的样式时,浏览器都会先从该节点的普遍属性(比如body里设置的全局样式)开始,再去应用该节点的具体属性。还有要注意的是,每个浏览器都有自己默认的样式表,因此很多时候这棵CSSOM树只是对这张默认样式表的部分替换。
3. 生成render树
DOM树和CSSOM树合并生成render树
简单描述这个过程:
DOM树从根节点开始遍历可见节点,这里之所以强调了“可见”,是因为如果遇到设置了类似display: none;的不可见节点,在render过程中是会被跳过的(但visibility: hidden; opacity: 0这种仍旧占据空间的节点不会被跳过render),保存各个节点的样式信息及其余节点的从属关系。
4. Layout 布局
有了各个节点的样式信息和属性,但不知道各个节点的确切位置和大小,所以要通过布局将样式信息和属性转换为实际可视窗口的相对大小和位置。
5. Paint 绘制
万事俱备,最后只要将确定好位置大小的各节点,通过GPU渲染到屏幕的实际像素。
Tips
- 在上述渲染过程中,前3点可能要多次执行,比如js脚本去操作dom、更改css样式时,浏览器又要重新构建DOM、CSSOM树,重新render,重新layout、paint;
- Layout在Paint之前,因此每次Layout重新布局(reflow 回流)后都要重新出发Paint渲染,这时又要去消耗GPU;
- Paint不一定会触发Layout,比如改个颜色改个背景;(repaint 重绘)
- 图片下载完也会重新出发Layout和Paint;
何时触发reflow和repaint
- reflow(回流): 根据Render Tree布局(几何属性),意味着元素的内容、结构、位置或尺寸发生了变化,需要重新计算样式和渲染树;
- repaint(重绘): 意味着元素发生的改变只影响了节点的一些样式(背景色,边框颜色,文字颜色等),只需要应用新样式绘制这个元素就可以了;
- reflow回流的成本开销要高于repaint重绘,一个节点的回流往往回导致子节点以及同级节点的回流;