当浏览器从服务器接收到页面的HTML响应时,在屏幕上绘制像素之前需要采取许多步骤。浏览器为页面的初始绘制需要执行的顺序称为“关键渲染路径” (CRP)。
CRP知识对于了解如何改善站点性能非常有用。CRP分为6个阶段-
- 构造DOM树
- 构造CSSOM树
- 运行JavaScript
- 创建渲染树
- 生成布局
- 绘画

1.构造DOM树
DOM(文档对象模型)树是完全解析的HTML页面的对象表示。从根元素开始,<html>
将为页面上的每个元素/文本创建节点。嵌套在其他元素中的元素表示为子节点,每个节点都包含该元素的完整属性。例如,<a>
元素将具有href
与其节点关联的属性。
以这个样本文件为例-
<html>
<head>
<title>Understanding the Critical Rendering Path</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<h1>Understanding the Critical Rendering Path</h1>
</header>
<main>
<h2>Introduction</h2>
<p>Lorem ipsum dolor sit amet</p>
</main>
<footer>
<small>Copyright 2017</small>
</footer>
</body>
</html>
这将创建以下DOM树-

关于HTML的一件好事是它可以部分执行。无需加载完整的文档即可使内容开始出现在页面上。但是,其他资源(CSS和JavaScript)可能会阻止页面的呈现。
2.构造CSSOM树
CSSOM(CSS对象模型)是与DOM关联的样式的对象表示。它以与DOM相似的方式表示,但包括每个节点的关联样式,无论它们是显式声明的还是隐式继承的。
在上述style.css
文档的文件中,我们具有以下样式-
body { font-size: 18px; }
header { color: plum; }
h1 { font-size: 28px; }
main { color: firebrick; }
h2 { font-size: 20px; }
footer { display: none; }
这将创建以下CSSOM树-

CSS被视为 “渲染阻止资源” 。这意味着如果不首先完全解析资源,则无法构建渲染树。与HTML不同,由于CSS具有继承级联性质,因此不能部分使用。稍后在文档中定义的样式可以覆盖和更改先前定义的样式。因此,如果我们在解析整个样式表之前开始使用样式表中较早定义的CSS样式,则可能会遇到应用了错误CSS的情况。这意味着,在我们进入下一阶段之前,必须对CSS进行完全解析。
CSS文件仅适用于当前设备,才被视为渲染阻止。该<link rel="stylesheet">
标签可以接受一个media
属性,我们可以在其中指定任何媒体查询其内的样式应用到。例如,如果我们有一个样式表,其media属性为orientation:landscape
,并且我们正在以纵向模式查看页面,则该资源将不被视为渲染阻止。
CSS也可以是 “脚本阻止”。这是因为JavaScript文件必须等待CSSOM构造完成后才能运行。
3.运行JavaScript
JavaScript被视为 “解析器阻止资源”。这意味着HTML文档本身的解析已被JavaScript阻止。
当解析器到达一个<script>
标签时,无论是内部标签还是外部标签,它都会停止获取(如果是外部标签)并运行它。这就是为什么,如果我们有一个JavaScript文件引用了文档中的元素,则必须将其放在该文档的外观之后。
为了避免JavaScript被解析器阻止,可以通过应用async
属性异步加载它。
<script async src="script.js">
4.创建渲染树
渲染树是DOM和CSSOM的组合。它是一棵树,代表最终将在页面上呈现的内容。这意味着它仅捕获可见的内容,并且不包括例如使用CSS被CSS隐藏的元素display: none
。
使用上面的示例DOM和CSSOM,将创建以下渲染树-

5.生成布局
布局是决定视口大小的要素,它为依赖于它的CSS样式(例如百分比或视口单位)提供了上下文。视口大小由文档头中提供的meta视口标签确定,或者,如果未提供标签,则使用默认视口宽度980px。
例如,最常见的元视口值是将视口大小设置为与设备宽度相对应-
<meta name="viewport" content="width=device-width,initial-scale=1">
如果用户在宽度为例如1000px的设备上访问网页,则尺寸将基于该单位。视口的一半将是500px,10vw将是100px,依此类推。
6.绘画
最后,在“绘画”步骤中,页面的可见内容可以转换为要在屏幕上显示的像素。
绘制步骤需要花费多少时间取决于DOM的大小以及所应用的样式。某些样式比其他样式需要执行更多工作。例如,复杂的渐变背景图像比简单的纯色背景需要更多的时间。
放在一起
要查看正在处理的关键渲染路径,我们可以在DevTools中对其进行检查。在Chrome浏览器中,它位于“时间轴”标签下(在Canary中,不久后成为Chrome稳定版,它已重命名为Performance)。
举例来说,我们上面的示例HTML(带有添加的<script>
标记)-
<html>
<head>
<title>Understanding the Critical Rendering Path</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<h1>Understanding the Critical Rendering Path</h1>
</header>
<main>
<h2>Introduction</h2>
<p>Lorem ipsum dolor sit amet</p>
</main>
<footer>
<small>Copyright 2017</small>
</footer>
<script src="main.js"></script>
</body>
</html>
如果我们查看页面加载的事件日志,就会得到以下信息:

- 发送请求-已发送index.html的GET请求
- 解析HTML并发送请求-开始解析HTML和DOM。发送对style.css和main.js的GET请求
- 解析样式表-为style.css创建的CSSOM
- 评估脚本-评估main.js
- 布局-基于HTML中的元视口标记生成布局
- 绘画-在文档上绘画像素
基于此信息,我们可以决定如何优化“关键渲染路径”。
网友评论