相对=预载

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

¥The preload value of the <link> element's rel attribute lets you declare fetch requests in the HTML's <head>, specifying resources that your page will need very soon, which you want to start loading early in the page lifecycle, before browsers' main rendering machinery kicks in. This ensures they are available earlier and are less likely to block the page's render, improving performance. Even though the name contains the term load, it doesn't load and execute the script but only schedules it to be downloaded and cached with a higher priority.

基础

¥The basics

你最常使用 <link> 加载 CSS 文件来设置页面样式:

¥You most commonly use <link> to load a CSS file to style your page with:

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

然而,在这里,我们将使用 relpreload,这会将 <link> 变成我们想要的任何资源的预加载器。你还需要指定:

¥Here however, we will use a rel value of preload, which turns <link> into a preloader for any resource we want. You will also need to specify:

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

一个简单的例子可能如下所示(参见我们的 JS 和 CSS 示例源还住):

¥A simple example might look like this (see our JS and CSS example source, and also live):

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> 元素,但发现的资源越晚且它们越大,好处就越明显。例如:

¥Here we preload our CSS and JavaScript files so they will be available as soon as they are required for the rendering of the page later on. This example is trivial, as the browser probably discovers the <link rel="stylesheet"> and <script> elements in the same chunk of HTML as the preloads, but the benefits can be seen much more clearly the later resources are discovered and the larger they are. For example:

  • 从 CSS 内部指向的资源,例如字体或图片。
  • JavaScript 可以请求的资源,例如导入的脚本。

preload 还有其他优点。使用 as 指定要预加载的内容类型允许浏览器:

¥preload has other advantages too. Using as to specify the type of content to be preloaded allows the browser to:

  • 存储在缓存中以备将来请求,并在适当的情况下重用资源。
  • 将正确的 内容安全政策 应用于资源。
  • 为其设置正确的 Accept 请求标头。

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

¥What types of content can be preloaded?

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

¥Many content types can be preloaded. The possible as attribute values are:

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

注意:fontfetch 预加载需要设置 crossorigin 属性;见下面的 支持 CORS 的获取

¥Note: font and fetch preloading requires the crossorigin attribute to be set; see CORS-enabled fetches below.

注意:HTML 规范中有关于这些值和它们期望使用的 Web 功能的更多详细信息 - 请参阅 链接类型 "preload"。另请注意,as 属性可以采用的值的完整列表由 Fetch 规范控制 - 请参阅 请求目的地

¥Note: There's more detail about these values and the web features they expect to be consumed by in the HTML spec — see Link type "preload". Also note that the full list of values the as attribute can take is governed by the Fetch spec — see request destinations.

包括 MIME 类型

¥Including a MIME type

<link> 元素可以接受 type 属性,该属性包含元素指向的资源的 MIME 类型。这在预加载资源时特别有用 - 浏览器将使用 type 属性值来确定它是否支持该资源,并且仅在支持时才下载它,如果不支持则忽略它。

¥<link> elements can accept a type attribute, which contains the MIME type of the resource the element points to. This is especially useful when preloading resources — the browser will use the type attribute value to work out if it supports that resource, and will only download it if so, ignoring it if not.

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 的用户来说,这使得下载的图片有望更小。

¥The code in the example above causes the image/avif image to be preloaded only in supporting browsers — and for users who have image/avif support in their browsers, causes the image/avif image to actually be used (since it's the first <source> specified). That makes the image download hopefully smaller for users who have image/avif support in their browsers.

请注意,对于浏览器同时支持 image/avifimage/webp 的用户,如果在该代码中还指定了 <link rel="preload" href="flower.webp" as="image" type="image/webp"> 元素,则 image/avifimage/webp 图片都将被预加载 - 即使实际上只使用其中之一。

¥Note that for users whose browsers have both image/avif and image/webp support, if in that code a <link rel="preload" href="flower.webp" as="image" type="image/webp"> element were also specified, then both the image/avif and image/webp images would be preloaded — even though only one of them would actually be used.

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

¥Therefore, specifying preloading for multiple types of the same resource is discouraged. Instead, the best practice is to specify preloading only for the type the majority of your users are likely to actually use. That's why the code in the example above doesn't specify preloading for the image/webp image.

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

¥However, the lack of preloading doesn't prevent the image/webp image from actually being used by those who need it: for users whose browsers don't have image/avif support but do have image/webp support, the code in the example above does still cause the image/webp image to be used — but it does so without also causing it to also be preloaded unnecessarily for the majority of other users.

支持 CORS 的获取

¥CORS-enabled fetches

当预加载启用 CORS 时获取的资源(例如 fetch()XMLHttpRequestfonts)时,需要特别注意在 <link> 元素上设置 crossorigin 属性。即使提取不是跨源的,也需要将属性设置为匹配资源的 CORS 和凭据模式。

¥When preloading resources that are fetched with CORS enabled (e.g. fetch(), XMLHttpRequest or fonts), special care needs to be taken to setting the crossorigin attribute on your <link> element. The attribute needs to be set to match the resource's CORS and credentials mode, even when the fetch is not cross-origin.

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

¥As mentioned above, one interesting case where this applies is font files. Because of various reasons, these have to be fetched using anonymous-mode CORS (see Font fetching requirements).

我们以这个案例为例。你可以看到完整的 GitHub 上的示例源代码也看到直播):

¥Let's use this case as an example. You can see the full example source code on GitHub (also see it live):

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 模式与最终的字体资源请求相匹配。

¥Not only are we providing the MIME type hints in the type attributes, but we are also providing the crossorigin attribute to make sure the preload's CORS mode matches the eventual font resource request.

包括媒体

¥Including media

<link> 元素的一个很好的特性是它们能够接受 media 属性。这些可以接受 媒体类型 或成熟的 媒体查询,允许你进行响应式预加载!

¥One nice feature of <link> elements is their ability to accept media attributes. These can accept media types or full-blown media queries, allowing you to do responsive preloading!

让我们看一个示例(在 GitHub 上查看 - 源代码活生生的例子):

¥Let's look at an example (see it on GitHub — source code, live example):

html
<head>
  <meta charset="utf-8" />
  <title>Responsive preload example</title>

  <link
    rel="preload"
    href="bg-image-narrow.png"
    as="image"
    media="(max-width: 600px)" />
  <link
    rel="preload"
    href="bg-image-wide.png"
    as="image"
    media="(min-width: 601px)" />

  <link rel="stylesheet" href="main.css" />
</head>
<body>
  <header>
    <h1>My site</h1>
  </header>

  <script>
    const mediaQueryList = window.matchMedia("(max-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 来执行此操作(更多信息请参阅 测试媒体查询)。

¥We include media attributes on our <link> elements so that a narrow image is preloaded if the user has a narrow viewport, and a wider image is loaded if they have a wide viewport. We use Window.matchMedia / MediaQueryList to do this (see Testing media queries for more).

这使得该字体更有可能可用于页面渲染,从而减少 FOUT(无样式文本的闪烁)。

¥This makes it much more likely that the font will be available for the page render, cutting down on FOUT (flash of unstyled text).

这不必局限于图片,甚至相同类型的文件 - 大胆思考!如果用户使用带宽和 CPU 可能更有限的窄屏幕,你也许可以预加载并显示一个简单的 SVG 图;或者如果用户的资源更丰富,则可以预加载复杂的 JavaScript 块,然后使用它来渲染交互式 3D 模型 。

¥This doesn't have to be limited to images, or even files of the same type — think big! You could perhaps preload and display a simple SVG diagram if the user is on a narrow screen where bandwidth and CPU is potentially more limited, or preload a complex chunk of JavaScript then use it to render an interactive 3D model if the user's resources are more plentiful.

脚本和预加载

¥Scripting and preloads

注意:如果你正在使用 JavaScript 模块,请改用 <link rel="modulepreload">

¥Note: Use <link rel="modulepreload"> instead if you are working with JavaScript modules.

这些预加载的另一个好处是你可以使用脚本执行它们。例如,这里我们创建一个 HTMLLinkElement 实例,然后将其附加到 DOM:

¥Another nice thing about these preloads is that you can execute them with script. For example, here we create a HTMLLinkElement instance, then attach it to the DOM:

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

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

¥This means that the browser will preload the myscript.js file, but not actually use it yet. To use it, you could do this:

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

当你想要预加载脚本,然后推迟执行直到你需要它时,这非常有用。

¥This is useful when you want to preload a script, but then defer execution until exactly when you need it.

规范

Specification
HTML Standard
# link-type-preload

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看

¥See also