缓慢的渲染时间也会让您的用户感到沮丧,并可能导致他们放弃您的页面。
1.8 秒对于 First Contentful Paint 很重要!
HTTP Archive从前约 700 万个 URL 收集数据。Lighthouse使用此数据来确定表现最佳的网站。然后将“绿色”级别设置在性能改进增加而收益递减的点上。
HTTP Archive(HTTP存档通过定期爬网web上的顶级站点来跟踪web是如何构建的,并记录有关获取的资源、使用的web平台API和特性的详细信息)
关键渲染路径是什么
我们在文件中编写 HTML、CSS 和 JavaScript,然后将这些文件传送到浏览器。浏览器将这些文件转换为您通过关键渲染路径看到的页面。步骤是:
-
下载HTML
-
阅读 HTML,同时:
- 构建文档对象模型(DOM)
- 注意
<link>样式表的标签并下载CSS
-
阅读 CSS 并构建CSS 对象模型(CSSOM)
-
将 DOM 和 CSSOM 组合成一个渲染树
-
使用渲染树,计算布局(每个元素的大小和位置)
-
绘制或渲染页面上的像素
什么是渲染阻塞资源
渲染阻塞资源是在关键渲染路径上“按暂停”的文件。它们会中断一个或多个步骤。
HTML 在技术上是渲染阻塞,因为您需要它来创建 DOM。如果没有 HTML,我们甚至都没有要呈现的页面。
然而,HTML 通常不是我们问题的原因......
CSS 是渲染阻塞。浏览器在创建 CSSOM 之前需要它,这会阻止所有后续步骤。一旦浏览器遇到样式表<link>或<style>标签,它就必须下载并解析内容。然后它必须在渲染的其余部分结束之后创建 CSSOM。您可以在图中的三角形点处看到这一点。在创建 CSSOM 和 DOM 之前,渲染树无法继续。
JavaScript 可以呈现阻塞。当浏览器遇到要同步运行的脚本时,它将停止 DOM 创建,直到脚本运行完毕。
此外,如果 CSS 出现在脚本之前,则在创建 CSSOM 之前不会执行脚本。这是因为 JavaScript 也可以与 CSSOM 交互,我们不希望它们之间出现竞争条件。
CSS 会阻止脚本执行,而 JavaScript 会阻止 DOM 的构建!
注意: 图像和字体不会阻止渲染。
为什么它们对性能很重要
渲染阻塞资源可能会引发网络性能的一连串故障。第一次绘制变慢,这会导致最大内容绘制 (LCP) 变慢。LCP 是现在用于计算您的搜索引擎排名的核心 Web Vitals 之一。
搜索引擎优化对于发现您的网站很重要。性能对于将访问者留在您的页面上至关重要。如果页面未在 3 秒内加载,则页面放弃率会显着增加。
如何测试我的网站的渲染阻止资源?
如果您在 Lighthouse 中未能通过此指标,那么您已经找到了一种测试方法。
我们的网站上都有阻止渲染的资源(所有 CSS!)。当它显着影响我们的性能时,问题就会出现。发生这种情况时,Lighthouse 会对其进行标记,我们应该对此采取措施。
渲染阻塞资源的 Lighthouse 候选包括脚本和样式:
<script>中的标签<head>至少不具有以下属性之一:async,defer,module- 没有属性或不匹配的媒体查询
<link>中的样式表标签(例如,)<head>``disabled``print
如果您未通过此指标,您的 Lighthouse 结果将如下所示:
Lighthouse 列出了bootstrap、Google Fonts 样式表、JQuery 脚本。让我们再深入一些。让我们检查
<head>对样品失效地点。它向我们展示了 2 个样式表,然后是 2 个脚本:
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css?family=Roboto:100,100i,300,300i,400,400i,500,500i,700,700i,900,900i"
rel="stylesheet">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous">
</script>
<script src="./jquery-3.5.1.js"></script>
<title>Document</title>
</head>
Lighthouse 可以标记这 2 个初始样式表中的任何一个。这次失败的根本原因是:
- 前 2 个样式表阻止 2 个同步脚本运行。浏览器必须首先下载样式表并创建 CSSOM。
- 浏览器在下载、解析和执行这 2 个脚本之前无法构建 DOM 的其余部分。
另一种测试渲染阻塞资源的方法是使用WebPageTest。WebPageTest 是性能分析的下一步。如果您输入一个 URL,它将在真实的移动设备上运行性能测试。测试完成后,单击中间运行的瀑布。每个渲染阻塞资源都会有一个橙色圆圈,旁边有一个白色的 X
如何删除阻塞渲染的资源?
是时候填补那个漏洞并修复我们的网站了。让我们深入研究 CSS 和 JavaScript。我们的目标不是消除所有渲染阻塞资源,而是降低它们对性能的影响。Lighthouse 指标有助于确定您何时到达该点。
为关键渲染路径优化 CSS
对于我们的 CSS,我们希望
- 最小化我们的样式的大小
- 并提供给客户快速和有效
我要问的第一个问题是:
我需要所有这些依赖项吗?
不要跳过第一个问题。最小化任何资产总大小的最简单方法是消灭它。把它夷为平地。例如,12 种 Google 字体似乎过多。我尽量将我的网络字体减少到最多 3-4 个样式集。
最小化 CSS 总量的下一个最简单的方法是最小化它。缩小是构建工具删除未使用的空白的过程。更少的字符 = 更小的尺寸 = 更快的下载。如果您使用的是 CSS 包,请确保使用它的缩小版本。下一步是使用构建工具自动最小化所有 CSS。示例工具包括 Gulp、Grunt、webpack 和 Parcel。Snowpack和Vite是有趣的新工具。
接下来,我会尝试将我的 CSS 分解成更小的块。理想情况下,我们只想交付我们将实际使用的 CSS。您可以看到有多少 CSS(和 JavaScript)实际上与Chrome Dev Tools 中的Coverage drawer一起使用。
- 打开开发工具
- 按 Cmd + Shift + P 打开快捷菜单
- 输入“Coverage”,然后选择“Show Coverage”
您可以单击重新加载按钮开始新的覆盖率分析。界面如下:
如果您的 CSS 总字节数很小,那么未使用的百分比就变得不那么重要了。例如,我的页面中有许多超过 90% 的未使用。因为我的 CSS 总量很小,所以我的 Lighthouse 分数仍然在 97-100 左右。
请注意,它仅适用于迄今为止使用的样式(或脚本)。当您交互或调整页面大小时,这些数字会上升。
您的目标不一定是 0% 未使用。但是,如果您看到大红条和大量未使用字节,则是时候减少初始渲染所需的 CSS。删除依赖项、使用代码拆分或内联关键 CSS 并推迟其余部分。
如果您有很多非屏幕样式,请考虑将它们提取到自己的样式表中。然后在<link>标签上使用媒体查询。例如:
<link href="styles/main.css" type="text/css" rel="stylesheet" media="screen">
<!-- Only downloaded for print: -->
<link href="styles/main_print.css" type="text/css" rel="stylesheet" media="print">
最后,不要@import在你的样式表中使用来加载更多的样式表。浏览器直到稍后才会发现它。最好<link>在 HTML 中使用标签加载它们。
针对关键渲染路径优化 JavaScript
正如我之前提到的,JavaScript 是解析器阻塞的。这意味着它会阻塞 DOM 构建,直到它完成执行。像 CSS 一样,我们想要:
- 最小化我们脚本的大小
- 并提供给客户快速和有效
Coverage 抽屉还会分析您的脚本。您可以过滤 CSS 和 JavaScript 之间的结果。同样,要问自己的第一个问题是:
我需要所有这些依赖项吗?
JavaScript 是我们最昂贵的资产,而且容易膨胀。删除未使用的依赖项。此外,根据需要使用code-splitting(按需加载)、tree-shaking(按需引入)或延迟加载功能。您的构建工具是所有这些策略的朋友。
让我们谈谈如何有效地交付我们的 JavaScript。我见过的最好的理解 async vs defer vs module 的图表来自HTML 规范:
- 无属性:在脚本下载和执行期间,HTML 解析器被阻止。
- defer:HTML 解析器没有被阻止。浏览器在识别脚本时下载脚本。它仅在完成创建 DOM 后才执行脚本。
- async:HTML 解析器在脚本执行期间被阻止。浏览器在识别脚本时下载脚本。下载后,脚本会阻塞 HTML 解析器,直到执行完成。
- module:行为类似于 defer 但可以管理 ES6 模块导入。
做出明智的选择。在大多数情况下,您会想要defer或async优化关键渲染路径。如果您有一个必须同步运行的内联脚本,请测试将其移动到 HTML 中的样式上方。
结论
渲染阻塞资源会引发一系列性能问题。这些性能问题会导致不满意的用户更快地放弃您的页面。
Lighthouse 和 Coverage 工具可以帮助您识别此问题并评估您的最佳选择。我们学会了:
- 减少我们的 CSS 和 JavaScript 字节,
- 延迟加载非关键 CSS 和 JavaScript,以及
- 使用
defer,async或module对我们的脚本属性。