Images à chargement différé

Les images peuvent s'afficher sur une page Web parce qu'elles sont intégrées dans le code HTML sous forme d'éléments <img> ou d'images de fond CSS. Dans cet article, vous allez découvrir comment effectuer le chargement différé des deux types d'images.

Images intégrées

Les candidats au chargement différé les plus courants sont les images utilisées dans les éléments <img>. Pour les images intégrées, nous proposons trois options de chargement différé, que vous pouvez utiliser conjointement pour une meilleure compatibilité entre les navigateurs:

Utiliser le chargement différé au niveau du navigateur

Chrome et Firefox sont tous deux compatibles avec le chargement différé avec l'attribut loading. Cet attribut peut être ajouté aux éléments <img>, ainsi qu'aux éléments <iframe>. La valeur lazy indique au navigateur de charger immédiatement l'image si elle se trouve dans la fenêtre d'affichage, et d'extraire les autres images lorsque l'utilisateur fait défiler la page à proximité.

Consultez le champ loading du tableau de compatibilité des navigateurs de MDN pour en savoir plus sur la compatibilité des navigateurs. Si le navigateur n'est pas compatible avec le chargement différé, l'attribut est ignoré et les images sont chargées immédiatement, comme d'habitude.

Pour la plupart des sites Web, l'ajout de cet attribut aux images intégrées permet d'améliorer les performances et d'éviter aux utilisateurs de charger des images auxquelles ils n'auraient jamais accès. Si vous disposez d'un grand nombre d'images et que vous souhaitez vous assurer que les utilisateurs de navigateurs non compatibles avec le chargement différé ne prennent pas en charge l'avantage du chargement différé, vous devez combiner ce comportement avec l'une des méthodes décrites ci-après.

Pour en savoir plus, consultez Chargement différé au niveau du navigateur pour le Web.

Utiliser l'observateur d'intersection

Pour émuler le chargement différé des éléments <img>, nous utilisons JavaScript afin de vérifier s'ils se trouvent dans la fenêtre d'affichage. Si c'est le cas, leurs attributs src (et parfois srcset) sont renseignés avec les URL du contenu image souhaité.

Si vous avez déjà écrit du code de chargement différé, vous avez peut-être accompli votre tâche à l'aide de gestionnaires d'événements tels que scroll ou resize. Bien que cette approche soit la plus compatible avec tous les navigateurs, les navigateurs récents offrent un moyen plus performant et efficace de vérifier la visibilité des éléments via l'API Intersection Observer.

Il est plus facile à utiliser et à lire que du code en s'appuyant sur divers gestionnaires d'événements, car il vous suffit d'enregistrer un observateur pour surveiller les éléments au lieu d'écrire un code fastidieux de détection de la visibilité des éléments. Il ne vous reste plus qu'à décider quoi faire lorsqu'un élément est visible. Supposons que vous utilisiez ce schéma de balisage de base pour vos éléments <img> chargés en différé:

<img class="lazy" src="placeholder-image.jpg" data-src="image-to-lazy-load-1x.jpg" data-srcset="image-to-lazy-load-2x.jpg 2x, image-to-lazy-load-1x.jpg 1x" alt="I'm an image!">

Vous devez vous concentrer sur trois éléments pertinents de ce balisage:

  1. L'attribut class, avec lequel vous sélectionnerez l'élément dans JavaScript.
  2. L'attribut src, qui référence une image d'espace réservé qui apparaîtra lors du premier chargement de la page
  3. Les attributs data-src et data-srcset, qui sont des attributs d'espace réservé contenant l'URL de l'image que vous chargerez une fois l'élément dans la fenêtre d'affichage.

Voyons maintenant comment utiliser Intersection Observer en JavaScript pour charger des images en différé à l'aide de ce schéma de balisage:

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

  if ("IntersectionObserver" in window) {
    let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          let lazyImage = entry.target;
          lazyImage.src = lazyImage.dataset.src;
          lazyImage.srcset = lazyImage.dataset.srcset;
          lazyImage.classList.remove("lazy");
          lazyImageObserver.unobserve(lazyImage);
        }
      });
    });

    lazyImages.forEach(function(lazyImage) {
      lazyImageObserver.observe(lazyImage);
    });
  } else {
    // Possibly fall back to event handlers here
  }
});

Lors de l'événement DOMContentLoaded du document, ce script interroge le DOM pour tous les éléments <img> avec une classe lazy. Si l'observateur d'intersection est disponible, créez un observateur qui exécute un rappel lorsque les éléments img.lazy entrent dans la fenêtre d'affichage.

Intersection Observer est disponible dans tous les navigateurs récents. Par conséquent, l'utiliser comme polyfill pour loading="lazy" garantira que le chargement différé sera disponible pour la plupart des visiteurs.

Images dans CSS

Bien que les tags <img> soient le moyen le plus courant d'utiliser des images sur des pages Web, les images peuvent également être appelées via la propriété CSS background-image (et d'autres propriétés). Le chargement différé au niveau du navigateur ne s'applique pas aux images de fond CSS. Vous devez donc envisager d'autres méthodes si vous disposez d'images de fond à charger en différé.

Contrairement aux éléments <img> qui se chargent quelle que soit leur visibilité, le comportement de chargement d'image en CSS implique davantage de spéculation. Lorsque les modèles de documents et d'objets CSS et l'arborescence de rendu sont créés, le navigateur examine la manière dont le CSS est appliqué à un document avant de demander des ressources externes. Si le navigateur a déterminé qu'une règle CSS impliquant une ressource externe ne s'applique pas au document tel qu'il est en cours de construction, le navigateur ne la demande pas.

Ce comportement spéculatif peut être utilisé pour différer le chargement des images dans CSS en utilisant JavaScript pour déterminer quand un élément se trouve dans la fenêtre d'affichage, puis en appliquant à cet élément une classe qui applique un style qui appelle une image de fond. Cela permet de télécharger l'image au moment où vous en avez besoin et non lors du chargement initial. Prenons l'exemple d'un élément qui contient une grande image de héros en arrière-plan:

<div class="lazy-background">
  <h1>Here's a hero heading to get your attention!</h1>
  <p>Here's hero copy to convince you to buy a thing!</p>
  <a href="/buy-a-thing">Buy a thing!</a>
</div>

L'élément div.lazy-background contient normalement l'image de fond du héros appelée par un code CSS. Toutefois, dans cet exemple de chargement différé, vous pouvez isoler la propriété background-image de l'élément div.lazy-background via une classe visible ajoutée à l'élément lorsqu'il se trouve dans la fenêtre d'affichage:

.lazy-background {
  background-image: url("hero-placeholder.jpg"); /* Placeholder image */
}

.lazy-background.visible {
  background-image: url("hero.jpg"); /* The final image */
}

À partir de là, utilisez JavaScript pour vérifier si l'élément se trouve dans la fenêtre d'affichage (avec Intersection Observer !), puis ajoutez la classe visible à l'élément div.lazy-background à ce moment-là, qui charge l'image:

document.addEventListener("DOMContentLoaded", function() {
  var lazyBackgrounds = [].slice.call(document.querySelectorAll(".lazy-background"));

  if ("IntersectionObserver" in window) {
    let lazyBackgroundObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          entry.target.classList.add("visible");
          lazyBackgroundObserver.unobserve(entry.target);
        }
      });
    });

    lazyBackgrounds.forEach(function(lazyBackground) {
      lazyBackgroundObserver.observe(lazyBackground);
    });
  }
});

Effets sur le Largest Contentful Paint (LCP)

Le chargement différé est une excellente optimisation qui réduit à la fois la consommation globale des données et les conflits sur le réseau au démarrage en reportant le chargement des images au moment où elles sont réellement nécessaires. Cela peut améliorer le temps de démarrage et réduire le traitement sur le thread principal en réduisant le temps nécessaire au décodage des images.

Toutefois, le chargement différé est une technique qui peut avoir un impact négatif sur le LCP Largest Contentful Paint de votre site Web si vous en acceptez trop. Il convient d'éviter les images à chargement différé qui s'affichent dans la fenêtre d'affichage au démarrage.

Lorsque vous utilisez des chargeurs différés basés sur JavaScript, évitez le chargement différé des images dans la fenêtre d'affichage, car ces solutions utilisent souvent un attribut data-src ou data-srcset comme espace réservé pour les attributs src et srcset. Le problème est que le chargement de ces images sera retardé, car le scanner de préchargement du navigateur ne les trouve pas au démarrage.

Même l'utilisation du chargement différé au niveau du navigateur pour le chargement différé d'une image dans la fenêtre d'affichage peut avoir un effet inverse. Lorsque loading="lazy" est appliqué à une image dans la fenêtre d'affichage, cette image est retardée jusqu'à ce que le navigateur sache qu'elle se trouve dans la fenêtre d'affichage, ce qui peut affecter le LCP d'une page.

Ne jamais d'images à chargement différé qui sont visibles dans la fenêtre d'affichage au démarrage. Ce modèle aura un impact négatif sur le LCP de votre site, et donc sur l'expérience utilisateur. Si vous avez besoin d'une image au démarrage, chargez-la le plus rapidement possible au démarrage en évitant le chargement différé.

Bibliothèques à chargement différé

Dans la mesure du possible, utilisez le chargement différé au niveau du navigateur. Toutefois, si vous vous trouvez dans une situation où cela n'est pas possible (par exemple, un grand nombre d'utilisateurs utilisent encore des navigateurs plus anciens), vous pouvez utiliser les bibliothèques suivantes pour charger des images en différé:

  • lazysizes est une bibliothèque de chargement différé dotée de fonctionnalités complètes qui permet de charger des images et des iFrames de manière différée. Le modèle qu'il utilise est assez semblable aux exemples de code présentés ici, dans la mesure où il se lie automatiquement à une classe lazyload sur les éléments <img> et vous oblige à spécifier des URL d'image dans les attributs data-src et/ou data-srcset, dont le contenu est échangé en attributs src et/ou srcset, respectivement. Il utilise l'observateur d'intersection (que vous pouvez émuler) et peut être étendu avec un certain nombre de plug-ins pour effectuer des opérations telles que le chargement différé de vidéos. En savoir plus sur l'utilisation des tailles différées
  • vanilla-lazyload est une option légère pour les images à chargement différé, les images de fond, les vidéos, les iFrames et les scripts. Il exploite Intersection Observer, prend en charge les images responsives et permet le chargement différé au niveau du navigateur.
  • lozad.js est une autre option légère qui n'utilise que l'outil Intersection Observer. Par conséquent, il est très performant, mais il devra être émulé avant que vous puissiez l'utiliser sur des navigateurs plus anciens.
  • Si vous avez besoin d'une bibliothèque de chargement différé spécifique à React, envisagez d'utiliser react-lazyload. Bien qu'il n'utilise pas Intersection Observer, il fournit une méthode familière de chargement différé des images pour les personnes habituées au développement d'applications avec React.