通过消除渲染阻塞 CSS 和 JavaScript 来提高网站性能
在我之前的文章中,我谈到了如何通过实现带有回退的原生延迟加载来提高我的个人网站的 Lighthouse 分数。
另一个提高我的性能和 Lighthouse 分数的重要改进是消除渲染阻塞资源。
关键和非关键资源
当我们通常构建一个项目时,我们喜欢将我们需要的一切都包含在内——所有样式、JavaScript 插件、JavaScript 代码、字体、图像等。我们通常这样做是为了确保在开发项目时不会发生异步加载错误。
实际情况是,浏览器在网站加载时需要加载、解析并运行我们包含的所有内容,这会导致首次渲染(没有缓存资源)不必要地变慢。这被称为渲染阻塞,因为浏览器浪费时间和资源来解析初始页面加载时不必要的代码,而无法显示页面内容。
当我们查看我们的资源(CSS、JavaScript、字体等)时,我们可以将它们分为两类:
- 关键资源——对页面核心功能至关重要的代码。
- 非关键资源- 页面核心功能中未使用的代码以及页面加载后或用户交互时运行的代码。
那么让我们看看如何处理关键和非关键的 CSS 和 JavaScript 资源。
处理关键 CSS
关键 CSS 指的是对首屏内容进行样式设置所必需的样式。首屏内容是指用户首次加载页面时可见的内容(页面顶部)。
为了将关键 CSS 添加到页面,我们需要从 CSS 样式表中删除这些样式,并将它们直接添加到元素<style>
内的标签中的 HTML 中<head>
。
<head>
<!-- ... -->
<style>
/* Add critical styles here */
</style>
<!-- ... -->
</head>
这种方法可能会稍微增加 HTML 文档的大小,但如果您使用 GZIP 或 Brotli 等压缩算法来传送 HTML,这些变化就微不足道了。
将关键 CSS 直接添加到 HTML 文档可确保这些样式在第一次绘制(初始加载)时被解析和应用。
处理非关键 CSS
为了使关键 CSS 生效,我们需要告诉浏览器如何处理非关键 CSS 并显示页面。这样还能让我们在加载其他非关键 CSS 时继续使用网站。根据网速,您甚至可能感觉不到其他样式的加载。
为了处理非关键 CSS,我们需要改变包含这些样式的 CSS 文件的加载方式。
<head>
<!-- ... -->
<link crossorigin rel="preload" href="/path/to/styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/path/to/styles.css"></noscript>
<!-- ... -->
</head>
乍一看这可能像是一种 hack,但这是一种非常聪明且有效的 CSS 加载方法,并且具有适当的回退功能:
link rel="preload" as="style"
以非渲染阻塞的方式加载 CSS 文件。onload="this.onload=null;this.rel='stylesheet'"
确保站点加载后CSS文件被解析并加载,并且该onload
功能被删除。noscript
如果 JavaScript 不可用,fallback 可确保 CSS 以标准方式加载。
还需要注意的是,我们可以以同样有效的方式加载 Google 字体样式表!
<link crossorigin rel="preload" href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;600&display=swap" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;600&display=swap"></noscript>
Firefox 问题和 IE 处理
在撰写本文时,Firefox 存在一个与预加载 CSS 相关的错误。这种加载非关键 CSS 的有效方法目前在 Firefox 上无法正常工作,但应该很快就会修复。
您可能需要为不支持预加载或存在问题的浏览器(例如 Firefox)提供回退功能。幸运的是,使用内联 JavaScript 可以轻松实现这一点。
<script>
var isIE = !!window.MSInputMethodContext && !!document.documentMode;
var isFirefox = navigator.userAgent.toLowerCase().indexOf("firefox") > -1;
if (isIE || isFirefox) {
var pageStylesheet = document.createElement("link");
pageStylesheet.rel = "stylesheet";
pageStylesheet.type = "text/css";
pageStylesheet.href = "/path/to/styles.css";
document.head.appendChild(pageStylesheet);
}
</script>
对于不支持预加载的 Firefox 和 IE 浏览器,我们只需要在body
关闭标签之前添加此代码即可将常规link
元素插入元素中。head
处理关键 JavaScript
我们处理关键 JavaScript 的方式与处理关键 CSS 的方式类似,即将其内联到 HTML 代码中。需要注意的是,我们需要在结束标记script
之前使用标签插入关键 JavaScript 代码body
。这样可以确保 JavaScript 不会阻塞内容渲染,并且所有可用的 DOM 节点都已创建并可供 JavaScript 代码使用。
<body>
<!-- ... -->
<script>
/* Inlined JavaScript code */
</script>
</body>
处理非关键 JavaScript
defer
我们只需向标签添加或async
标签即可处理非关键 JavaScript script
(内联 JavaScript 或从加载的 JavaScript src
)。
- 我们用于
defer
需要整个 DOM 或相对执行顺序很重要的脚本。它告诉浏览器先加载页面,然后在后台加载脚本。 - 我们用于
async
可以按任意顺序执行的独立脚本。这些脚本不会等待任何其他脚本,并且可以与其他脚本并行加载async
。
<script defer src="/path/to/script.js"></script>
<script async src="/path/to/script.js"></script>
提升性能和 Lighthouse 评分
在我的个人网站上,我按照文章中描述的方式处理了关键和非关键的 CSS 和 JavaScript。实施这种现代方法后,我消除了阻塞渲染的非关键 CSS 和 JavaScript,从而提升了我的 Lighthouse 评分和整体性能!
这些文章都是咖啡带来的灵感。所以,如果你喜欢我的文章,觉得它有用,不妨请我喝杯咖啡!我会非常感激的。
感谢您花时间阅读这篇文章。如果您觉得它有用,请点赞 ❤️ 或 🦄,分享并评论。
文章来源:https://dev.to/prototyp/improving-website-performance-by-elimination-render-blocking-css-and-javascript-28ei