Types de liens : preload
========================

La valeur `preload` de l'attribut `rel` de l'élément `<link>` permet de déclarer des requêtes à récupérer dans la partie `<head>` du HTML de la page, en spécifiant les ressources dont votre page va avoir besoin dans peu de temps, et qu'il serait souhaitable de charger le plus tôt possible, avant que le rendu de la page par le navigateur ne commence. Cela permet de s'assurer que les ressources sont disponibles plus tôt et qu'elles auront moins de chances de bloquer le rendu de la page, ce qui améliore les performances.

Les bases
---------

Pour charger un fichier CSS permettant de styler une page, on utilise le plus souvent l'élément `<link>` de la manière suivante :


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


Ici, nous allons utiliser la valeur `preload` sur l'attribut `rel`, ce qui transformera l'élément `<link>` en outil de préchargement utilisable pour n'importe quelle ressource. Nous devrons aussi indiquer :

* le chemin de la ressource dans l'attribut `href` ;
* le type de ressource dans l'attribut `as` ;

Voici un exemple simple (voir nos fichiers JS et CSS d'exemple et le résultat obtenu) :


```html
<head>
  <meta charset="utf-8" />
  <title>Exemple de préchargement JS et CSS</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>Balles rebondissantes</h1>
  <canvas></canvas>

  <script src="main.js" defer></script>
</body>
```


Dans l'exemple ci-dessus, nous préchargeons nos fichiers CSS et JavaScript afin qu'ils puissent être disponibles dès qu'ils sont nécessaires pour le rendu de la page. Cet exemple est trivial, car le navigateur va probablement découvrir en même temps les balises de préchargement, le `<link rel="stylesheet">` et le `<script>`, mais le bénéfice sera bien plus visible si les ressources sont plus nombreuses, plus lourdes et chargées à différents endroits. Par exemple :

* les ressources qui sont chargées depuis un fichier CSS, comme certaines polices et images ;
* les ressources inclues par des fichiers JavaScript, comme des fichiers JSON, d'autres scripts importés ou des services web ;
* les fichiers image et vidéos plus importants.

`preload` dispose aussi d'autres avantages. L'utilisation de l'attribut `as` pour spécifier le type de contenu à précharger permet au navigateur de :

* prioriser les ressources se chargeant avec davantage de précision ;
* les stocker dans le cache pour de futures requêtes, ce qui permet de réutiliser les ressources si c'est pertinent ;
* appliquer la bonne stratégie de sécurité du contenu aux ressources ;
* mettre en place les bons en-têtes de requêtes `Accept` pour les ressources.
### Quels types de contenu peuvent être préchargés ?

De nombreux différents types de contenu peuvent être préchargés. Les valeurs possibles de l'attribut `as` sont les suivantes :

* `audio` : fichier audio, typiquement intégré avec l'élément `<audio>` ;
* `document` : un document HTML destiné à être embarqué dans une `<frame>` ou dans une `<iframe>` ;
* `embed` : une ressource à embarquer dans un élément `<embed>` ;
* `fetch` : une ressource accessible via une requête `fetch` ou `XHR`, comme un `ArrayBuffer` ou un fichier JSON ;
* `font` : un fichier de police ;
* `image` : un fichier image ;
* `object` : une ressource à embarquer à l'intérieur d'un élément `<object>` ;
* `script` : un fichier JavaScript ;
* `style` : une feuille de styles CSS ;
* `track` : un fichier WebVTT ;
* `worker` : un
 *web worker*
 JavaScript ou un
 *worker*
 partagé ;
* `video` : un fichier vidéo, typiquement intégré avec l'élément `<video>`.

**Note :** le préchargement de l'élément `video` est inclut dans la spécification *Preload* mais n'est pas encore implémenté par les navigateurs.

**Note :** pour davantage de détails sur ces valeurs et sur la façon dont la spécification *Preload* prévoit de les traiter, consultez *link element extensions* (en anglais). Notez également que la liste complète des valeurs acceptées par l'attribut `as` est déterminé par la spécification *Fetch* — voir la spécification *request destinations* (en anglais).

Inclure un type MIME
--------------------

Les éléments `<link>` peuvent accepter un attribut `type`, contenant le type MIME de la ressource vers laquelle pointe le document. Ceci est tout spécialement utile lorsque l'on effectue un préchargement des ressources – le navigateur utilisera alors l'attribut `type` pour vérifier s'il prend en charge la ressource et la télécharger si c'est le cas, ou l'ignorer dans le cas contraire.

Vous pouvez voir un exemple de ce fonctionnement dans notre vidéo d'exemple (voir le code source complet ou la version exécutable en direct), utilisant le bout de code proposé ci-dessous. À noter que si ce code ne lancera pas de préchargement effectif sur aucun navigateur – le préchargement des vidéos n'est encore implémenté sur aucun navigateur – cela permet d'illustrer le fonctionnement général du préchargement.


```html
<head>
  <meta charset="utf-8" />
  <title>Exemple de préchargement de vidéo</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>
      Votre navigateur ne prend pas en charge les vidéos HTML5. Voici un
      <a href="sintel-short.mp4">lien vers le fichier vidéo en remplacement</a>.
    </p>
  </video>
</body>
```


Le code de l'exemple ci-dessus permet le préchargement de la `video/mp4` uniquement sur les navigateurs qui prennent en charge cette fonctionnalité et pour les personnes ayant un navigateur prenant en charge le format `video/mp4` (car ce format est le premier élément `<source>` spécifié). Cela devrait rendre le lecteur vidéo plus ergonomique et plus *responsive* pour ces personnes.

Concernant les personnes disposant d'un navigateur prenant en charge tout aussi bien les formats `video/mp4` et `video/webm` support, il est important de noter que si un élément `<link rel="preload" href="sintel-short.webm" as="video" type="video/webm">` est aussi spécifié, alors **les deux formats `video/mp4` et `video/webm` seront préchargés** — même si un seul d'entre eux est utilisé.

En conclusion, il est déconseillé de précharger de multiple formats pour la même ressource. La bonne pratique est plutôt de précharger uniquement le type de média qu'utilise la majorité des personnes qui visitent votre site. C'est pourquoi le code fourni en exemple ne précharge pas la vidéo au format `video/webm`.

Cependant, l'absence de préchargement n'empêche pas la vidéo `video/webm` d'être utilisée par les personnes qui en ont besoin : pour les navigateurs qui ne prennent pas en charge le format `video/mp4` mais qui prennent en charge le format `video/webm` alors le code de l'exemple permettra toujours d'utiliser la vidéo au format `video/webm` — cela évitera simplement de précharger inutilement une ressource pour la plupart des navigateurs.

Récupération de l'activation du *CORS*
--------------------------------------

Lors du préchargement des ressources analysées par des fonctions activant le CORS (partage des ressources entre origines multiples), comme par exemple `fetch()`, `XMLHttpRequest` ou fonts), une attention particulière doit être portée à la mise en place de l'attribut `crossorigin` sur l'élément `<link>`. L'attribut à besoin d'être mis en place pour faire correspondre le *CORS* de la ressource et le mode d'identification, même s'il ne s'agit pas d'une ressource ayant une origine différente de celle de la page.

Comme mentionné ci-dessus, un cas de figure intéressant est celui qui s'applique aux fichiers de polices. Pour plusieurs raisons, celles-ci doivent être analysées en utilisant le mode anonyme du *CORS* (voir cet article en anglais : *Font fetching requirements*).

Voici un cas d'utilisation. Vous trouverez le code source complet sur GitHub ainsi qu'une démonstration :


```html
<head>
  <meta charset="utf-8" />
  <title>Exemple de préchargement de police Web</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>
```


En plus de fournir un type MIME avec l'attribut `type`, ce code utilise un attribut `crossorigin` afin de s'assurer que le préchargement du *CORS* correspond à la requête de chargement de la police.

Inclure des médias
------------------

Une autre belle fonctionnalité de l'élément `<link>` concerne leur capacité à accepter les attributs `media`. Il peut accepter les requêtes de types de médias ou encore des *media queries* complètes, ce qui vous permet de faire du préchargement *responsive* !

Voici un exemple. Vous pouvez consulter son code source sur GitHub ou étudier un exemple de démonstration :


```html
<head>
  <meta charset="utf-8" />
  <title>Exemple de préchargement responsive</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>Mon 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>
```


Dans cet exemple nous incluons les attributs `media` dans notre élément `<link>` pour qu'une image plus fine soit préchargée si la personne visitant le site dispose d'un écran plus petit, et pour qu'une image plus large soit chargée sur les écrans plus larges. Pour cela, nous utilisons `Window.matchMedia` et `MediaQueryList` (en-US) (consultez la page Tester les requêtes média en JavaScript pour en savoir plus).

Cela augmente les chances que la police sera disponible lors du rendu de la page, et diminue les risques de *FOUT* (pour *flash of unstyled text*, soit « flash de texte sans mis en forme » en français).

Il sera dommage de limiter le préchargement aux images, voyez plus loin ! On pourrait imaginer de précharger l'affichage d'un diagramme SVG si le visiteur se trouve sur un petit écran avec une bande passante ou une disponibilité CPU plus limitée, ou encore de précharger des morceaux de JavaScript complexes utilisés pour faire fonctionner une modélisation 3D interactive uniquement si les ressources du visiteur sont suffisantes.

Scripts et préchargement
------------------------

Une autre fonctionnalité notable est la possibilité d'exécuter le préchargement à l'aide d'un script. Par exemple, voici la création d'une instance `HTMLLinkElement` (en-US) qui est ensuite attachée au *DOM* :


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


Cela signifie que le navigateur va précharger le fichier `myscript.js`, mais ne va pas réellement l'utiliser directement. Pour l'utiliser, vous pouvez faire ceci :


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


C'est utile lorsque vous voulez précharger un script mais repousser son exécution au moment exact où vous en avez réellement besoin.

Autres ressources concernant les mécanismes de préchargement
------------------------------------------------------------

D'autres fonctionnalités de préchargement sont disponibles, mais sachez qu'aucune d'entre elle n'est aussi adaptée à l'objectif recherché que `<link rel="preload">`. En voici la liste :

* `<link rel="prefetch">` est pris en charge depuis quelque temps par les navigateurs, mais est destinée à la récupération préalable des ressources qui vont être utilisées lors de la ***prochaine*** page visitée/chargée (par exemple lorsque vous vous rendrez sur une autre page du site). C'est une bonne chose, mais ce n'est pas utile pour la page en cours de chargement ! Par ailleurs, les navigateurs donnent une priorité plus faible à `prefetch` qu'à `preload` — la page courante est prioritaire par rapport à la page suivante. Consultez la FAQ sur le préchargement des liens pour plus de détails ;
* `<link rel="prerender">` effectue le rendu une page spécifiée en arrière-plan, ce qui permet d'accélerer son chargement si la personne visitant le site se rend sur cette page par la suite. Du fait du gaspillage potentiel de bande passante pour les visiteurs (on charge des éléments sans savoir si on en aura besoin), Chrome traite l'instruction `prerender` comme une instruction NoState prefetch ;
* `<link rel="subresource">` 
Non-standard
 était pris en charge par Chrome il y a quelques temps et était destiné à gérer la même chose que `preload`, mais il y avait un problème : il n'y avait aucun moyen de définir une priorité sur les éléments à charger (`as` n'existait pas encore), donc toutes les ressources étaient chargées avec la même priorité (la plus faible) ;
* Il y a un grand nombre de scripts de chargements de ressources disponibles un peu partout, mais aucun ne peut avoir la puissance d'une file de priorisation gérée directement par le navigateur. De plus, ces scripts sont sujets à des problèmes de performances similaires.
Spécifications
--------------

| Specification |
| --- |
| HTML Standard # link-type-preload |

Compatibilité des navigateurs
-----------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Voir aussi
----------

* *Preload: What Is It Good For?*
 par Yoav Weiss (en anglais)