Vidéo à chargement différé

Publié le 16 août 2019

Comme pour les éléments Image, vous pouvez également charger de manière différée les vidéos. Les vidéos sont généralement chargées avec l'élément <video>. Toutefois, pour les vidéos hébergées sur d'autres services tels que YouTube, des <iframe> peuvent être utilisés (dans ce cas, consultez l'article sur les iframes à chargement différé).

La méthode de chargement paresseux de <video> dépend du cas d'utilisation, car il existe plusieurs solutions.

Pour les vidéos qui ne sont pas lues automatiquement

Il est généralement recommandé d'éviter la lecture automatique des vidéos, car elle laisse le contrôle à l'utilisateur. Dans ce cas, spécifier l'attribut preload sur l'élément <video> est le meilleur moyen d'éviter de charger l'intégralité de la vidéo:

<video controls preload="none" poster="one-does-not-simply-placeholder.jpg">
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>

L'exemple précédent utilise un attribut preload avec une valeur de none pour empêcher les navigateurs de précharger toute donnée vidéo. L'attribut poster attribue à l'élément <video> un espace réservé qui occupera l'espace pendant le chargement de la vidéo.

Dans la plupart des navigateurs, preload est défini par défaut sur metadata et une partie de la vidéo est préchargée à l'aide de l'en-tête Content-Range. Cela peut entraîner le téléchargement de plus de données que souhaité, en particulier si l'en-tête Content-Range n'est pas compatible avec le navigateur. Même si cette fonctionnalité est prise en charge, les navigateurs ne peuvent pas savoir à quels octets les métadonnées sont stockées, et elles ne sont pas nécessairement stockées au début du fichier. Par conséquent, la meilleure solution pour éviter le chargement de la vidéo consiste à spécifier none et à utiliser preload="none".

Vous pouvez améliorer cette fonctionnalité pour précharger les métadonnées lorsque l'utilisateur pointe sur la vidéo avec un attribut onmouseenter (ou avec le gestionnaire d'événements mouseenter équivalent):

<video controls
  preload="none"
  poster="one-does-not-simply-placeholder.jpg"
  onmouseenter="event.target.setAttribute('preload','metadata')">
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>

Cela permet de réduire le délai de lecture de la vidéo et d'afficher sa durée dès qu'elle est lancée.

Les vidéos peuvent être qualifiées de candidats à la LCP. Une image poster se charge plus rapidement qu'une vidéo. Par conséquent, si une image est candidate au LCP, vous devez utiliser une image poster, mais aussi la précharger avec une valeur d'attribut fetchpriority de "high":

<link rel="preload" href="one-does-not-simply-placeholder.jpg" as="image" fetchpriority="high">
<video controls preload="none"
  poster="one-does-not-simply-placeholder.jpg"
  onmouseenter="event.target.setAttribute('preload','metadata')">
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>

Pour les vidéos servant de remplacement aux GIF animés

Les vidéos en lecture automatique sont généralement utilisées pour les animations rapides de type GIF. Bien que les GIF animés soient largement utilisés, ils sont inférieurs aux équivalents vidéo à plusieurs égards, en particulier en termes de taille de fichier. Les GIF animés peuvent atteindre plusieurs mégaoctets de données. Les vidéos de qualité visuelle similaire ont tendance à être beaucoup plus petites.

L'utilisation de l'élément <video> pour remplacer les GIF animés n'est pas aussi simple que celle de l'élément <img>. Les GIF animés présentent trois caractéristiques:

  1. Elles sont lues automatiquement lors du chargement.
  2. Elles sont en boucle continue (mais ce n'est pas toujours le cas).
  3. Elles ne contiennent pas de piste audio.

Pour ce faire avec l'élément <video>, procédez comme suit:

<video autoplay muted loop playsinline>
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>

Les attributs autoplay, muted et loop sont explicites. playsinline est nécessaire pour que la lecture automatique puisse avoir lieu sur iOS. Vous disposez désormais d'un remplacement de la vidéo au format GIF qui fonctionne sur toutes les plates-formes. Mais comment procéder au chargement différé ? Pour commencer, modifiez votre balisage <video> en conséquence:

<video class="lazy" autoplay muted loop playsinline width="610" height="254" poster="one-does-not-simply.jpg">
  <source data-src="one-does-not-simply.webm" type="video/webm">
  <source data-src="one-does-not-simply.mp4" type="video/mp4">
</video>

Vous remarquerez l'ajout de l'attribut poster, qui vous permet de spécifier un espace réservé pour occuper l'espace de l'élément <video> jusqu'à ce que la vidéo soit chargée de manière différée. Comme dans les exemples de chargement différé <img>, stockez l'URL de la vidéo dans l'attribut data-src de chaque élément <source>. À partir de là, utilisez du code JavaScript semblable aux exemples de chargement paresseux d'images basés sur Intersection Observer:

document.addEventListener("DOMContentLoaded", function() {
  var lazyVideos = [].slice.call(document.querySelectorAll("video.lazy"));

  if ("IntersectionObserver" in window) {
    var lazyVideoObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(video) {
        if (video.isIntersecting) {
          for (var source in video.target.children) {
            var videoSource = video.target.children[source];
            if (typeof videoSource.tagName === "string" && videoSource.tagName === "SOURCE") {
              videoSource.src = videoSource.dataset.src;
            }
          }

          video.target.load();
          video.target.classList.remove("lazy");
          lazyVideoObserver.unobserve(video.target);
        }
      });
    });

    lazyVideos.forEach(function(lazyVideo) {
      lazyVideoObserver.observe(lazyVideo);
    });
  }
});

Lorsque vous chargez de manière différée un élément <video>, vous devez itérer sur tous les éléments <source> enfants et remplacer leurs attributs data-src par des attributs src. Ensuite, vous devez déclencher le chargement de la vidéo en appelant la méthode load de l'élément. Le fichier multimédia commencera alors à être lu automatiquement conformément à l'attribut autoplay.

Cette méthode vous permet de disposer d'une solution vidéo qui émule le comportement des GIF animés, mais qui n'entraîne pas la même utilisation intensive des données que les GIF animés. Vous pouvez également charger de manière différée ce contenu.

Bibliothèques de chargement différé

Les bibliothèques suivantes peuvent vous aider à charger de manière différée des vidéos:

  • vanilla-lazyload et lozad.js sont des options ultra légères qui n'utilisent que Intersection Observer. Par conséquent, ils sont très performants, mais doivent être polyfilled avant de pouvoir les utiliser dans les anciens navigateurs.
  • yall.js est une bibliothèque qui utilise Intersection Observer et qui utilise des gestionnaires d'événements en cas de défaillance. Il peut également charger de manière différée les images poster vidéo à l'aide d'un attribut data-poster.
  • Si vous avez besoin d'une bibliothèque de chargement différé spécifique à React, vous pouvez envisager d'utiliser react-lazyload. Bien qu'il n'utilise pas Intersection Observer, il fournit une méthode familière de chargement paresseux des images pour les développeurs d'applications React.

Chacune de ces bibliothèques de chargement différé est bien documentée, avec de nombreux modèles de balisage pour vos différents projets de chargement différé.