rel=preload
Baseline 广泛可用 *
<link>
元素的 rel
属性的 preload
值允许你在 HTML 的 <head>
中声明抓取请求,指定页面很快将需要的资源。你希望在页面生命周期早期开始加载这些资源,赶在浏览器主要渲染机制启动之前。这确保它们能更早可用,并且不太可能阻塞页面渲染,从而提高性能。尽管名称中包含“加载”一词,但它并不会加载并执行脚本,而只是以更高的优先级安排其下载和缓存。
基本原理
你最常使用 <link>
来加载 CSS 文件以美化页面
<link rel="stylesheet" href="styles/main.css" />
然而,这里我们将使用 rel
值为 preload
,它将 <link>
转换为我们想要的任何资源的预加载器。你还需要指定
- 资源在
href
属性中的路径。 - 资源在
as
属性中的类型。
一个例子可能看起来像这样(参见我们的 JS 和 CSS 示例源代码,以及实时示例)
<head>
<meta charset="utf-8" />
<title>JS and CSS preload example</title>
<link rel="preload" href="style.css" as="style" />
<link rel="preload" href="main.js" as="script" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<h1>bouncing balls</h1>
<canvas></canvas>
<script src="main.js" defer></script>
</body>
这里我们预加载了 CSS 和 JavaScript 文件,以便它们在页面后续渲染需要时立即可用。这个例子很简单,因为浏览器可能在与预加载相同的 HTML 块中发现了 <link rel="stylesheet">
和 <script>
元素,但当资源发现得越晚且越大时,其优势会更加明显。例如
- CSS 内部指向的资源,如字体或图像。
- JavaScript 可以请求的资源,如导入的脚本。
preload
还有其他优点。使用 as
来指定要预加载的内容类型,允许浏览器
哪些类型的内容可以预加载?
许多内容类型都可以预加载。可能的 as
属性值有
fetch
:通过 fetch 或 XHR 请求访问的资源,如 ArrayBuffer、WebAssembly 二进制文件或 JSON 文件。font
:字体文件。image
:图像文件。script
:JavaScript 文件。style
:CSS 样式表。track
:WebVTT 文件。
注意: font
和 fetch
预加载需要设置 crossorigin
属性;请参阅下面的启用 CORS 的抓取请求。
注意: HTML 规范中对这些值以及它们预期被哪些 Web 功能消费有更详细的描述——请参阅 Link type "preload"。另请注意,as
属性可接受的完整值列表受 Fetch 规范管理——请参阅 request destinations。
包含 MIME 类型
<link>
元素可以接受一个 type
属性,其中包含元素指向的资源的 MIME 类型。这在预加载资源时特别有用——浏览器将使用 type
属性值来判断它是否支持该资源,如果支持则下载,否则忽略。
<head>
<meta charset="utf-8" />
<title>Image preload example</title>
<link rel="preload" href="flower.avif" as="image" type="image/avif" />
</head>
<body>
<picture>
<source src="flower.avif" type="image/avif" />
<source src="flower.webp" type="image/webp" />
<img src="flower.jpg" />
</picture>
</body>
上面示例中的代码导致 image/avif
图像仅在支持的浏览器中预加载——对于浏览器支持 image/avif
的用户,导致 image/avif
图像实际被使用(因为它是第一个指定的 <source>
)。这使得对于浏览器支持 image/avif
的用户来说,图像下载量有望更小。
请注意,对于浏览器同时支持 image/avif
和 image/webp
的用户,如果在该代码中也指定了 <link rel="preload" href="flower.webp" as="image" type="image/webp">
元素,那么 image/avif
和 image/webp
图像都将被预加载——即使最终只会使用其中一个。
因此,不鼓励为同一资源的多种类型指定预加载。相反,最佳实践是仅为大多数用户可能实际使用的类型指定预加载。这就是为什么上面示例中的代码没有为 image/webp
图像指定预加载。
然而,缺乏预加载并不能阻止 image/webp
图像被需要它的用户实际使用:对于浏览器不支持 image/avif
但支持 image/webp
的用户,上面示例中的代码仍然会导致 image/webp
图像被使用——但它这样做,而不会对大多数其他用户造成不必要的预加载。
启用 CORS 的抓取请求
当预加载启用 CORS 的资源(例如,fetch()
、XMLHttpRequest
或字体)时,需要特别注意在你的 <link>
元素上设置 crossorigin
属性。该属性需要设置为与资源的 CORS 和凭证模式匹配,即使抓取不是跨域的。
如上所述,一个有趣的适用情况是字体文件。由于各种原因,这些必须使用匿名模式 CORS 获取(参见 字体获取要求)。
让我们以这个案例为例。你可以在 GitHub 上查看完整的 示例源代码(也可以实时查看)
<head>
<meta charset="utf-8" />
<title>Web font example</title>
<link
rel="preload"
href="fonts/cicle_fina-webfont.woff2"
as="font"
type="font/woff2"
crossorigin />
<link
rel="preload"
href="fonts/zantroke-webfont.woff2"
as="font"
type="font/woff2"
crossorigin />
<link href="style.css" rel="stylesheet" />
</head>
<body>
…
</body>
我们不仅在 type
属性中提供了 MIME 类型提示,还提供了 crossorigin
属性,以确保预加载的 CORS 模式与最终的字体资源请求匹配。
包含媒体
<link>
元素的一个很好的特性是它们能够接受 media
属性。这些属性可以接受媒体类型或完整的媒体查询,允许你进行响应式预加载!
让我们看一个例子(在 GitHub 上查看——源代码,实时示例)
<head>
<meta charset="utf-8" />
<title>Responsive preload example</title>
<link
rel="preload"
href="bg-image-narrow.png"
as="image"
media="(width <= 600px)" />
<link
rel="preload"
href="bg-image-wide.png"
as="image"
media="(width > 600px)" />
<link rel="stylesheet" href="main.css" />
</head>
<body>
<header>
<h1>My site</h1>
</header>
<script>
const mediaQueryList = window.matchMedia("(width <= 600px)");
const header = document.querySelector("header");
if (mediaQueryList.matches) {
header.style.backgroundImage = 'url("bg-image-narrow.png")';
} else {
header.style.backgroundImage = 'url("bg-image-wide.png")';
}
</script>
</body>
我们在 <link>
元素上包含了 media
属性,这样如果用户视口较窄,则预加载窄图像;如果用户视口较宽,则加载宽图像。我们使用 Window.matchMedia
/ MediaQueryList
来实现这一点(有关更多信息,请参阅 测试媒体查询)。
这种技术也适用于其他资源类型。例如,与字体一起使用时,预加载使得字体在渲染时更有可能可用,从而减少了无样式文本闪烁 (FOUT) 的可能性。
这不必局限于图像,甚至不必局限于相同类型的文件——着眼大局!如果用户处于带宽和 CPU 可能更有限的窄屏幕上,你或许可以预加载并显示简化的 SVG 图表,或者如果用户资源更充足,则预加载复杂的 JavaScript 片段,然后使用它来渲染交互式 3D 模型。
脚本和预加载
注意: 如果你正在使用 JavaScript 模块,请改用 <link rel="modulepreload">
。
这些预加载的另一个优点是你可以用脚本执行它们。例如,这里我们创建一个 HTMLLinkElement
实例,然后将其附加到 DOM
const preloadLink = document.createElement("link");
preloadLink.href = "myscript.js";
preloadLink.rel = "preload";
preloadLink.as = "script";
document.head.appendChild(preloadLink);
这意味着浏览器将预加载 myscript.js
文件,但实际上尚未将其投入使用。要使用它,你可以这样做
const preloadedScript = document.createElement("script");
preloadedScript.src = "myscript.js";
document.body.appendChild(preloadedScript);
当你想要预加载一个脚本,但将执行推迟到你需要它的确切时间时,这很有用。
规范
规范 |
---|
HTML # 链接类型预加载 |
浏览器兼容性
加载中…
另见
- 推测性加载 用于比较
<link rel="preload">
和其他类似性能改进功能。 - 预加载:它有什么用? 作者:Yoav Weiss