rel="preload" によるコンテンツの先読み

この翻訳は不完全です。英語から この記事を翻訳 してください。

HTML の <head> 要素内において、 <link> 要素で rel 属性に preload を指定することで、読み込み後すぐにページに必要なリソース、つまりページ読み込みの過程の初期の、ブラウザの主なレンダリング機構が起動する前に、先読みを始めたいものを指定する宣言的なフェッチ要求を記述することができます。これにより、ページの最初のレンダリングがブロックされにくくなり、パフォーマンスが向上します。この記事では preload がどのように動作するのかについての基本的なガイドを提供します。

基本概念

ページのスタイルを指定するために CSS ファイルを読み込むとき、多くの場合は以下のようにつまらない <link> 要素を使用します。

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

しかしここで、 rel の値に preload を使用すると、 <link> 要素は利用したいかなりのリソースの先読み指示になります。基本的に、 href 属性に先読みするリソースのパスを指定することと、 as 属性に先読みするリソースの種類を指定することも必要です。

簡単な例は以下のようになります (JS and CSS example source および 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: <frame><iframe> の中に埋め込まれる HTML 文書。
  • embed: <embed> 要素の中に埋め込まれるリソース。
  • fetch: ArrayBuffer や JSON ファイルのような、フェッチまたは XHR 要求でアクセスされるリソース。
  • font: フォントファイル。
  • image: 画像ファイル。
  • object: <embed> 要素の中に埋め込まれるリソース。
  • script: JavaScript ファイル。
  • style: スタイルシート。
  • track: WebVTT ファイル。
  • worker: JavaScript ウェブワーカーまたは共有ワーカー。
  • video: Video file.

: preload の仕様で使用されると予想されるこれらの値について、もう少し詳細な情報は、 link element extensions を参照してください。また、フェッチの仕様の定義で管理されている as 属性の値の完全な一覧は、 request destinations を参照してください。

MIME タイプを含める

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

オリジンをまたいだフェッチ

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.

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.

スクリプトと先読み

Another nice thing about these preloads is that you can execute them completely with script if desired. For example, here we are creating a HTMLLinkElement instance, then attaching it to the DOM:

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

This means that the browser will preload the JavaScript file, but not actually use it yet.

To use it, you could do this when desired:

var 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 executing it until exactly when you need it.

他のリソースの先読み機構

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.

仕様策定状況

仕様書 策定状況 コメント
Preload
preload の定義
草案 preload の詳細。
HTML Living Standard
<link> の定義
現行の標準 preload の基本的な定義

ブラウザーの互換性

機能 Chrome Firefox (Gecko) Internet Explorer Opera Safari
基本サポート 50.0 未サポート[1] 未サポート 47 11
機能 Android Android Webview Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile Chrome for Android
基本サポート 56 50.0 未サポート[1] 未サポート (有) 11 50.0

[1] This feature was available in Firefox 56, but only for cacheable resources. It has been disabled in Firefox 57 because of various web compatibility issues (e.g. バグ 1405761). An improved version that works for non-cacheable resources is expected to land in Firefox 59.

関連情報

ドキュメントのタグと貢献者

 このページの貢献者: mfuji09
 最終更新者: mfuji09,