rel=preload

Baseline 广泛可用 *

此特性已得到良好确立,并可在多种设备和浏览器版本上运行。自 2021 年 1 月起,所有浏览器均已支持此特性。

* 此特性的某些部分可能存在不同级别的支持。

<link> 元素的 rel 属性的 preload 值允许你在 HTML 的 <head> 中声明抓取请求,指定页面很快将需要的资源。你希望在页面生命周期早期开始加载这些资源,赶在浏览器主要渲染机制启动之前。这确保它们能更早可用,并且不太可能阻塞页面渲染,从而提高性能。尽管名称中包含“加载”一词,但它并不会加载并执行脚本,而只是以更高的优先级安排其下载和缓存。

基本原理

你最常使用 <link> 来加载 CSS 文件以美化页面

html
<link rel="stylesheet" href="styles/main.css" />

然而,这里我们将使用 rel 值为 preload,它将 <link> 转换为我们想要的任何资源的预加载器。你还需要指定

  • 资源在 href 属性中的路径。
  • 资源在 as 属性中的类型。

一个例子可能看起来像这样(参见我们的 JS 和 CSS 示例源代码,以及实时示例

html
<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 来指定要预加载的内容类型,允许浏览器

  • 为将来的请求存储在缓存中,如果合适则重用资源。
  • 对资源应用正确的内容安全策略
  • 为其设置正确的 Accept 请求头。

哪些类型的内容可以预加载?

许多内容类型都可以预加载。可能的 as 属性值有

  • fetch:通过 fetch 或 XHR 请求访问的资源,如 ArrayBuffer、WebAssembly 二进制文件或 JSON 文件。
  • font:字体文件。
  • image:图像文件。
  • script:JavaScript 文件。
  • style:CSS 样式表。
  • track:WebVTT 文件。

注意: fontfetch 预加载需要设置 crossorigin 属性;请参阅下面的启用 CORS 的抓取请求

注意: HTML 规范中对这些值以及它们预期被哪些 Web 功能消费有更详细的描述——请参阅 Link type "preload"。另请注意,as 属性可接受的完整值列表受 Fetch 规范管理——请参阅 request destinations

包含 MIME 类型

<link> 元素可以接受一个 type 属性,其中包含元素指向的资源的 MIME 类型。这在预加载资源时特别有用——浏览器将使用 type 属性值来判断它是否支持该资源,如果支持则下载,否则忽略。

html
<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/avifimage/webp 的用户,如果在该代码中也指定了 <link rel="preload" href="flower.webp" as="image" type="image/webp"> 元素,那么 image/avifimage/webp 图像都将被预加载——即使最终只会使用其中一个。

因此,不鼓励为同一资源的多种类型指定预加载。相反,最佳实践是仅为大多数用户可能实际使用的类型指定预加载。这就是为什么上面示例中的代码没有为 image/webp 图像指定预加载。

然而,缺乏预加载并不能阻止 image/webp 图像被需要它的用户实际使用:对于浏览器不支持 image/avif 但支持 image/webp 的用户,上面示例中的代码仍然会导致 image/webp 图像被使用——但它这样做,而不会对大多数其他用户造成不必要的预加载。

启用 CORS 的抓取请求

当预加载启用 CORS 的资源(例如,fetch()XMLHttpRequest字体)时,需要特别注意在你的 <link> 元素上设置 crossorigin 属性。该属性需要设置为与资源的 CORS 和凭证模式匹配,即使抓取不是跨域的。

如上所述,一个有趣的适用情况是字体文件。由于各种原因,这些必须使用匿名模式 CORS 获取(参见 字体获取要求)。

让我们以这个案例为例。你可以在 GitHub 上查看完整的 示例源代码也可以实时查看

html
<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 上查看——源代码实时示例

html
<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

js
const preloadLink = document.createElement("link");
preloadLink.href = "myscript.js";
preloadLink.rel = "preload";
preloadLink.as = "script";
document.head.appendChild(preloadLink);

这意味着浏览器将预加载 myscript.js 文件,但实际上尚未将其投入使用。要使用它,你可以这样做

js
const preloadedScript = document.createElement("script");
preloadedScript.src = "myscript.js";
document.body.appendChild(preloadedScript);

当你想要预加载一个脚本,但将执行推迟到你需要它的确切时间时,这很有用。

规范

规范
HTML
# 链接类型预加载

浏览器兼容性

另见