Предварительная загрузка контента при помощи rel="preload"

Значение preload атрибута rel элемента <link> позволяет вам писать декларативные запросы на получение данных в элементе <head> вашего HTML, точно определяя ресурсы, которые понадобятся на вашей странице вскоре после загрузки и которые вы хотите загружать раньше в цикле загрузки страницы, до того как это сделает механизм отрисовки вашего браузера. Это гарантирует то, что нужные ресурсы будут доступны раньше и с меньшей вероятностью будут блокировать первую отрисовку страницы, что в свою очередь ведёт к улучшению производительности. Эта статья представляет собой базовое руководство о том, как работает preload.

Основы

Чаще всего вы используете простой <link> элемент когда загружаете CSS файлы со стилем вашей страницы:

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

Однако тут мы будем использовать тег rel со значением preload, чтобы превратить <link> элемент в предзагрузчик для любого файла какой мы только захотим. В начале вы должны указать путь до ваших файлов для предзагрузки в href и тип файла который будет загружатся в as.

Простой пример будет выглядеть так (посмотрите наш JS and CSS example source, и also live):

<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"></script>
</body>

Тут мы предзагрузили наш CSS и JavaScript файлы, чтобы они были доступны для рендеринга страницы чуть позже Этот пример отчасти банальный, но преимущества можно увидеть позже при рендеринге, особенно когда файлы много весят. Для примера как насчет ресурсов которые лежат снаружи CSS файла, такие как шрифты, картинки или большие фото и видео-файлы?

preload имеет и другие приемущества. Используйте as для указания типа контента и это позволит браузеру:

  • Устанавливать приоритеты загрузки более точно.
  • Соответствовать будущим запросам, используя тот же ресурс, если это необходимо.
  • Применять корректную content security policy для файлов.
  • Устанавливает корректные Accept запросы для его заголовка.

Какие типы контента могут быть предзагружены?

Много разного типа контента можно предварительно загрузить. Это основные доступные в качестве значения as атрибуты:

  • audio: Аудио файлы.
  • document: HTML документ предназначенный для <frame> or <iframe>.
  • embed: Ресурс который будет встроен в <embed> элемент.
  • fetch: Ресурс имеющий доступ к запросу на выборку или XHR, такой как файл ArrayBuffer или JSON.
  • font: Шрифты.
  • image: Картинки.
  • object: Ресурс встроенный в <embed> элемент.
  • script: JavaScript.
  • style: CSS таблица стилей.
  • track: WebVTT.
  • worker: A JavaScript web worker и shared worker.
  • video: Видео.

Заметка: Вы можете прочитать немного больше об этих значениях и веб-функциях, которыми они будут пользоваться, в спецификации Preload— link element extensions. Также обратите внимание, что полный список значений as атрибут может принимать зависит от определений в спецификации Fetch —  request destinations.

Including a MIME type

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

You can see an example of this in our video example (see the full source code, and also the live version):

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

  <link rel="preload" href="sintel-short.mp4" as="video" type="video/mp4">
</head>
<body>
  <video controls>
    <source src="sintel-short.mp4" type="video/mp4">
    <source src="sintel-short.webm" type="video/webm">
    <p>Your browser doesn't support HTML5 video. Here is a <a href="sintel-short.mp4">link to the video</a> instead.</p>
  </video>
</body>

So in this case, browsers that support MP4s will preload and use the MP4, making the video player hopefully smoother/more responsive for users. Browsers that don't support the MP4 can still load the WebM version, but don't get the advantages of preloading. This shows how preloading content can be combined with the philosophy of progressive enhancement.

Cross-origin fetches

If you've got your sites' CORS settings worked out properly, you can successfully preload cross-origin resources as long as you set a crossorigin attribute on your <link> element.

One interesting case in which this applies even if the fetch is not cross-origin is font files. Because of various reasons, these have to be fetched using anonymous mode CORS (see Font fetching requirements if you are interested in all the details).

Let's use this case as an example, firstly because font loading is a really good use case for preloading, and secondly, because it is easier than setting up a cross-origin request example. You can see the full example source code on GitHub (also see it live):

<head>
  <meta charset="utf-8">
  <title>Web font example</title>

  <link rel="preload" href="fonts/cicle_fina-webfont.eot" as="font" type="application/vnd.ms-fontobject" crossorigin="anonymous">
  <link rel="preload" href="fonts/cicle_fina-webfont.woff2" as="font" type="font/woff2" crossorigin="anonymous">
  <link rel="preload" href="fonts/cicle_fina-webfont.woff" as="font" type="font/woff" crossorigin="anonymous">
  <link rel="preload" href="fonts/cicle_fina-webfont.ttf" as="font" type="font/ttf" crossorigin="anonymous">
  <link rel="preload" href="fonts/cicle_fina-webfont.svg" as="font" type="image/svg+xml" crossorigin="anonymous">

  <link rel="preload" href="fonts/zantroke-webfont.eot" as="font" type="application/vnd.ms-fontobject" crossorigin="anonymous">
  <link rel="preload" href="fonts/zantroke-webfont.woff2" as="font" type="font/woff2" crossorigin="anonymous">
  <link rel="preload" href="fonts/zantroke-webfont.woff" as="font" type="font/woff" crossorigin="anonymous">
  <link rel="preload" href="fonts/zantroke-webfont.ttf" as="font" type="font/ttf" crossorigin="anonymous">
  <link rel="preload" href="fonts/zantroke-webfont.svg" as="font" type="image/svg+xml" crossorigin="anonymous">

  <link href="style.css" rel="stylesheet" type="text/css">
</head>
<body>
  ...
</body>

You'll see here that not only are we providing the MIME type hints in the type attributes, but we are also providing the crossorigin attribute to handle the CORS issue.

Including 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!

Let's look at a very simple example (see it on GitHub — source code, live example):

<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>
    var mediaQueryList = window.matchMedia("(max-width: 600px)");
    var 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>

You'll see that we are including media attributes on our <link> elements so that a narrow image is preloaded if the user is on a narrow screen device, and a wider image is loaded if they are on a wider screen device. We still need to attach the correct image to the header depending on the result — we use Window.matchMedia / MediaQueryList to do this (see Testing media queries for more information on this).

This makes it much more likely that the font will be available by the time the page render is complete, cutting down on FOUT (flash of unstyled text) issues.

Note that this doesn't have to be limited to images, or even files of the same type — think big! You could perhaps preload then 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

Ещё одна полезная вещь в этих предзагрузках, это то, что вы можете выполнять их полностью со скриптами, если необходимо. Например, мы сейчас создаём  экземпляр HTMLLinkElement, затем включим её в DOM:

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

Пдразумевается, что браузер загрузит JavaScript файл, но, пока не будет его применять.

Чтобы выполнить его, вы можете использовать следующую конструкцию:

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

Это полезно, когда вы хотите загрузить скрипт в кеш, но применять его только тогда, когда это необходимо.

Other resource preloading mechanisms

Other preloading features exist, but none are quite as fit for purpose as <link rel="preload">:

  • <link rel="prefetch"> has been supported in browsers for a long time, but it is intended for prefetching resources that will be used in the next navigation/page load (e.g. when you go to the next page). This is fine, but isn't useful for the current page! In addition, browsers will give prefetch resources a lower priority than preload ones — the current page is more important than the next one. See Link prefetching FAQ for more details.
  • <link rel="subresource"> was supported in Chrome a while ago, and was intended to tackle preloading resources for the current navigation/page load, but it had a problem — there was no way to work out a priority for fetching the items (as didn't exist back then), so they all ended up being fetched with fairly low priority, which didn't help the situation.
  • There are a number of script-based resource loaders out there, but they don't have any power over the browser's fetch prioritization queue, and are subject to much the same performance problems.

Specifications

Specification Status Comment
Preload
Определение 'preload' в этой спецификации.
Кандидат в рекомендации Further details of preload.
HTML Living Standard
Определение 'rel=preload' в этой спецификации.
Живой стандарт Definition of rel=preload.

Browser compatibility

Update compatibility data on GitHub
КомпьютерыМобильные
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome для AndroidFirefox для AndroidOpera для AndroidSafari on iOSSamsung Internet
preload
Экспериментальная
Chrome Полная поддержка 50Edge ? Firefox Нет поддержки 56 — 57
Замечания
Нет поддержки 56 — 57
Замечания
Замечания Disabled due to various web compatibility issues (e.g. bug 1405761).
IE ? Opera Полная поддержка 37Safari ? WebView Android Полная поддержка 50Chrome Android Полная поддержка 50Firefox Android Нет поддержки 56 — 57
Замечания
Нет поддержки 56 — 57
Замечания
Замечания Disabled due to various web compatibility issues (e.g. bug 1405761).
Opera Android ? Safari iOS ? Samsung Internet Android Полная поддержка 5.0

Легенда

Полная поддержка  
Полная поддержка
Нет поддержки  
Нет поддержки
Совместимость неизвестна  
Совместимость неизвестна
Экспериментальная. Ожидаемое поведение может измениться в будущем.
Экспериментальная. Ожидаемое поведение может измениться в будущем.
Смотрите замечания реализации.
Смотрите замечания реализации.

See also