关键渲染路径是指网页开始在浏览器中渲染之前所涉及的步骤。为了渲染网页,浏览器需要 HTML 文档本身以及渲染该文档所需的所有关键资源。
上一章的“一般 HTML 性能注意事项”模块介绍了如何将 HTML 文档发送到浏览器。不过,在本单元中,我们将重点了解浏览器在下载 HTML 文档以呈现网页后会执行哪些操作。
渐进式渲染
Web 本身就是分布式的。与在使用前安装的原生应用不同,浏览器无法依赖于网站是否具有呈现网页所需的所有资源。因此,浏览器非常擅长以渐进的方式呈现网页。原生应用通常有安装阶段和运行阶段。不过,对于网页和 Web 应用,这两个阶段之间的界限要模糊得多,浏览器的设计就是充分考虑了这一点。
浏览器一旦有资源来呈现网页,通常就会开始呈现。因此,选择的关键在于何时呈现:何时太早?
如果浏览器在仅包含一些 HTML 时就尽快呈现(但在没有任何 CSS 或必要的 JavaScript 之前),则网页会暂时看起来损坏,并且在最终呈现时会发生很大变化。与在初始呈现空白屏幕一段时间(直到浏览器拥有初始呈现所需的更多资源,从而提供更好的用户体验)相比,这种体验更差。
另一方面,如果浏览器等待所有资源可用,而不是执行任何顺序渲染,则用户将需要等待很长时间;如果网页在更早的时间点就已可用,则这种等待通常是没有必要的。
浏览器需要知道它应等待的资源数量下限,以避免呈现明显不佳的体验。另一方面,浏览器也不应等待过长时间才向用户显示内容。浏览器在执行初始渲染之前执行的一系列步骤称为关键渲染路径。
了解关键渲染路径有助于提高 Web 性能,因为这样可以确保您不会过度阻塞初始网页渲染。不过,同时请务必不要通过从关键渲染路径中移除初始渲染所需的资源,而导致渲染过早发生。
(关键)渲染路径
渲染路径包括以下步骤:
- 从 HTML 构建文档对象模型 (DOM)。
- 从 CSS 构建 CSS 对象模型 (CSSOM)。
- 应用会更改 DOM 或 CSSOM 的任何 JavaScript。
- 从 DOM 和 CSSOM 构建渲染树。
- 在页面上执行样式和布局操作,以查看哪些元素适合放置在哪里。
- 绘制内存中元素的像素。
- 如果像素有重叠,则合成像素。
- 将所有生成的像素实际绘制到屏幕上。
只有在完成所有这些步骤后,用户才能在屏幕上看到内容。
此渲染过程会重复进行多次。初始渲染会调用此进程,但随着影响网页渲染的更多资源变得可用,浏览器会重新运行此进程(或仅运行其部分内容),以更新用户看到的内容。关键渲染路径侧重于之前为初始渲染概述的过程,并依赖于初始渲染所需的关键资源。
关键渲染路径上有哪些资源?
浏览器需要等待一些关键资源下载完毕,才能完成初始渲染。这些资源包括:
- HTML 的一部分。
<head>
元素中存在阻塞渲染的 CSS。<head>
元素中会阻塞渲染的 JavaScript。
一个关键点是,浏览器会以流式方式处理 HTML。浏览器在获取网页 HTML 的任何部分后,便会立即开始处理它。然后,浏览器可以在接收网页的其余 HTML 之前决定如何渲染该标头(通常会这样做)。
请务必注意,对于初始渲染,浏览器通常不会等待以下操作:
- 所有 HTML。
- 字体。
- Images.
<head>
元素之外的非渲染阻塞 JavaScript(例如,放置在 HTML 末尾的<script>
元素)。<head>
元素之外的非渲染阻塞 CSS,或media
属性值不适用于当前视口的 CSS。
浏览器通常会将字体和图片视为在后续网页重新呈现期间填充的内容,因此它们无需延迟初始呈现。不过,这可能意味着,在初始渲染时会保留空白区域,而文本会隐藏,直到等待字体或图片可用。更糟糕的是,如果未为某些类型的内容预留足够的空间(尤其是在 HTML 中未提供图片尺寸的情况下),则当这些内容稍后加载时,网页的布局可能会发生变化。用户体验的这一方面可通过 Cumulative Layout Shift (CLS) 指标衡量。
<head>
元素对于处理关键渲染路径至关重要。因此,下一部分将对其进行详细介绍。优化 <head>
元素的内容是提升网站性能的关键方面。不过,目前,如需了解关键渲染路径,您只需知道 <head>
元素包含有关网页及其资源的元数据,但不包含用户可见的实际内容。可见内容包含在 <head>
元素后面的 <body>
元素中。在浏览器能够呈现任何内容之前,它需要同时拥有要呈现的内容以及有关如何呈现内容的元数据。
不过,<head>
元素中引用的资源并非全部都对初始页面呈现至关重要,因此浏览器只会等待那些重要的资源。若要确定哪些资源位于关键渲染路径中,您需要了解阻塞渲染和阻塞解析器的 CSS 和 JavaScript。
会阻塞渲染的资源
某些资源被视为非常重要,因此浏览器会暂停网页呈现,直到处理完这些资源。CSS 默认属于此类别。
当浏览器看到 CSS(无论是 <style>
元素中的内嵌 CSS,还是 <link rel=stylesheet href="...">
元素指定的外部引用资源)时,都会避免在下载并处理该 CSS 之前渲染任何其他内容。
资源阻止呈现并不一定意味着它会阻止浏览器执行任何其他操作。浏览器会尽可能提高效率,因此当浏览器发现需要下载 CSS 资源时,会请求该资源并暂停呈现,但仍会继续处理 HTML 的其余部分,并在此期间寻找其他工作。
会阻塞渲染的资源(例如 CSS)在被发现时会阻止网页的所有渲染。这意味着,某些 CSS 是否会阻塞渲染取决于浏览器是否发现了它们。某些浏览器(最初是 Firefox,现在也包括 Chrome)仅会阻止呈现呈现阻塞资源下方的内容。这意味着,对于关键的阻塞渲染路径,我们通常会关注 <head>
中的阻塞渲染资源,因为它们会有效阻止整个网页的渲染。
一个较新的创新是 blocking=render
属性,已添加到 Chrome 105 中。这样,开发者就可以在 <link>
、<script>
或 <style>
元素被处理之前,明确将其标记为会阻塞渲染,但同时仍允许解析器继续处理文档。
解析器阻塞资源
解析器阻塞资源是指会阻止浏览器继续解析 HTML 以寻找其他工作可做的内容的资源。JavaScript 默认是解析器阻塞型(除非明确标记为异步或延迟),因为 JavaScript 在执行时可能会更改 DOM 或 CSSOM。因此,在知道请求的 JavaScript 对网页 HTML 的全部影响之前,浏览器无法继续处理其他资源。因此,同步 JavaScript 会阻塞解析器。
解析器阻塞资源实际上也会阻塞渲染。由于解析器在完全处理解析阻塞资源之前无法继续,因此无法访问和呈现其后面的内容。在等待期间,浏览器可以呈现到目前为止收到的所有 HTML,但对于关键呈现路径而言,<head>
中的任何解析器阻塞资源实际上意味着所有网页内容都被阻止呈现。
阻塞解析器可能会带来巨大的性能开销,远远超过仅阻塞渲染所带来的开销。因此,浏览器会尝试使用辅助 HTML 解析器(称为预加载扫描器)在主 HTML 解析器被阻塞时下载即将使用的资源,以降低此开销。虽然不如实际解析 HTML 那样理想,但至少可以让浏览器中的网络功能在被屏蔽的解析器之前运行,这意味着它日后不太可能再次被屏蔽。
识别阻塞资源
许多性能审核工具都可以识别渲染和解析阻塞资源。WebPageTest 会在资源网址左侧用橙色圆圈标记会阻塞呈现的资源:
所有渲染阻塞资源都需要先下载并处理,然后才能开始渲染,这在瀑布流中用实心深绿色线表示。
Lighthouse 还会突出显示会阻塞呈现的资源,但方式更为细微,并且只有在资源确实延迟了网页呈现时才会突出显示。这有助于避免在您尽可能减少呈现阻塞的情况下出现误报。通过 Lighthouse 运行与上图中的 WebPageTest 相同的网页网址,只会将其中一个样式表单标识为渲染阻塞资源。
优化关键渲染路径
优化关键呈现路径包括缩短接收 HTML 的时间(由第一字节时间 (TTFB) 指标表示),如上一个模块中所详述,并减少呈现阻塞资源的影响。我们将在后续单元中探讨这些概念。
关键的内容渲染路径
长期以来,关键渲染路径一直关注初始渲染。不过,随着出现更多以用户为中心的网页性能指标,一些人开始质疑,关键渲染路径的端点应该是首次绘制,还是随后的某次包含更多内容的绘制。
另一种观点是,将重点放在内容渲染路径(或其他人称之为关键路径)中的 Largest Contentful Paint (LCP)(甚至 First Contentful Paint (FCP))所需时间。在这种情况下,您可能需要添加一些资源,这些资源不一定会阻塞(这是关键渲染路径的典型定义),但对于渲染内容丰富的绘制操作而言是必不可少的。
无论您对“关键”的确切定义是什么,了解导致任何初始渲染和关键内容延迟的原因都很重要。首次绘制用于衡量首次有可能为用户渲染任何内容的机会。理想情况下,这应该是一些有意义的内容,而不是背景颜色之类的内容。不过,即使没有内容,向用户呈现某些内容仍然有价值,这也是根据传统定义衡量关键渲染路径的论点。同时,衡量向用户呈现主要内容的时间也有价值。
确定包含内容的呈现路径
许多工具都可以识别 LCP 元素及其呈现时间。除了 LCP 元素之外,Lighthouse 还会帮助您确定 LCP 阶段以及每个阶段所花的时间,以便您了解应将优化工作重点放在哪些方面:
对于更复杂的网站,Lighthouse 还会在单独的审核中突出显示一系列关键请求:
此 Lighthouse 审核会监控以高优先级加载的所有资源,因此其中包括 Chrome 设为高优先级资源的 Web 字体和其他内容,即使这些资源实际上并未阻塞渲染也是如此。
知识测验
关键渲染路径是指什么?
关键渲染路径涉及哪些资源?
<head>
元素中存在阻塞渲染的 CSS。<head>
元素中会阻塞渲染的 JavaScript。为什么呈现阻塞是网页呈现的必要部分?
为什么 JavaScript 会阻止 HTML 解析器(假设 <script>
元素未指定 defer
、async
或 module
属性)?
<script>
将会阻塞解析器和呈现。下一步:优化资源加载
本单元介绍了浏览器呈现网页背后的一些理论,尤其是完成网页的初始呈现所需的条件。在下一个模块中,我们将了解如何优化资源加载,以便优化此渲染路径。