Bonnes pratiques concernant le chargement différé

Bien que les images et les vidéos à chargement différé présentent des avantages positifs et mesurables en termes de performances, ce n'est pas une tâche à prendre à la légère. Si vous vous trompez, cela pourrait avoir des conséquences inattendues. Par conséquent, il est important de garder à l'esprit les préoccupations suivantes.

Faites attention à la ligne de flottaison

Il peut être tentant de charger en différé toutes les ressources multimédias de la page avec JavaScript, mais vous devez résister à cette tentation. Tout ce qui se trouve au-dessus du pli ne doit pas être chargé en différé. Ces ressources doivent être considérées comme des ressources critiques et doivent donc être chargées normalement.

Le chargement différé retarde le chargement des ressources jusqu'à ce que le DOM soit interactif, lorsque le chargement des scripts est terminé et que leur exécution commence. Pour les images en dessous de la ligne de flottaison, ce n'est pas un problème, mais les ressources critiques situées au-dessus de la ligne de flottaison doivent être chargées avec l'élément <img> standard afin qu'elles s'affichent dès que possible.

Bien sûr, la position de la ligne de flottaison n'est pas aussi évidente de nos jours, lorsque les sites Web sont consultés sur un grand nombre d'écrans de tailles différentes. Ce qui se trouve au-dessus de la ligne de flottaison sur un ordinateur portable peut très bien se trouver en dessous sur les appareils mobiles. Il n'existe aucun conseil irréprochable pour répondre de manière optimale à cela dans toutes les situations. Vous devrez procéder à un inventaire des ressources essentielles de votre page et charger ces images de façon classique.

En outre, vous préférerez peut-être ne pas être aussi strict concernant la ligne de pliage que le seuil de déclenchement du chargement différé. Pour vos besoins, il peut être préférable d'établir une zone de tampon une certaine distance en dessous du pli afin que les images commencent à se charger bien avant que l'utilisateur les fasse défiler dans la fenêtre d'affichage. Par exemple, l'API Intersection Observer vous permet de spécifier une propriété rootMargin dans un objet d'options lorsque vous créez une instance IntersectionObserver. Cela donne aux éléments un tampon, ce qui déclenche un comportement de chargement différé avant que l'élément ne se trouve dans la fenêtre d'affichage:

let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
  // lazy-loading image code goes here
}, {
  rootMargin: "0px 0px 256px 0px"
});

Si la valeur de rootMargin ressemble à celles que vous spécifiez pour une propriété CSS margin, c'est parce que c'est le cas. Dans ce cas, la marge inférieure de l'élément observé (la fenêtre d'affichage du navigateur par défaut, mais peut être remplacée par un élément spécifique à l'aide de la propriété root) est étendue de 256 pixels. Cela signifie que la fonction de rappel s'exécute lorsqu'un élément image se trouve à moins de 256 pixels de la fenêtre d'affichage et que l'image commence à se charger avant que l'utilisateur ne la voie.

Pour obtenir le même effet dans les navigateurs qui ne sont pas compatibles avec Intersection Observer, utilisez le code de gestion des événements de défilement et ajustez votre vérification getBoundingClientRect pour inclure un tampon.

Décalage de mise en page et espaces réservés

Le chargement différé peut entraîner un décalage de la mise en page si aucun espace réservé n'est utilisé. Ces modifications peuvent désorienter les utilisateurs et déclencher des opérations de mise en page DOM coûteuses qui consomment des ressources système et contribuent aux à-coups. Vous pouvez, au minimum, utiliser un espace réservé de couleur unie occupant les mêmes dimensions que l'image cible, ou des techniques telles que LQIP ou SQIP qui suggèrent le contenu d'un élément multimédia avant son chargement.

Pour les balises <img>, src doit initialement pointer vers un espace réservé jusqu'à ce que cet attribut soit mis à jour avec l'URL finale de l'image. Utilisez l'attribut poster dans un élément <video> pour pointer vers une image d'espace réservé. De plus, utilisez les attributs width et height dans les balises <img> et <video>. Cela garantit que le passage des espaces réservés aux images finales ne modifiera pas la taille de rendu de l'élément lors du chargement du contenu multimédia.

Retards de décodage des images

Le chargement d'images volumineuses en JavaScript et leur dépôt dans le DOM peut corrompre le thread principal, ce qui entraîne le blocage de l'interface utilisateur pendant une courte période lors du décodage. Le décodage asynchrone des images à l'aide de la méthode decode avant de les insérer dans le DOM peut réduire ce type d'à-coups, mais sachez qu'il n'est pas encore disponible partout, et cela complexifie la logique de chargement différé. Si vous souhaitez l'utiliser, vous devez le vérifier. Vous trouverez ci-dessous comment utiliser Image.decode() avec un remplacement:

var newImage = new Image();
newImage.src = "my-awesome-image.jpg";

if ("decode" in newImage) {
  // Fancy decoding logic
  newImage.decode().then(function() {
    imageContainer.appendChild(newImage);
  });
} else {
  // Regular image load
  imageContainer.appendChild(newImage);
}

Consultez ce lien CodePen pour voir du code semblable à cet exemple en action. Si la plupart de vos images sont assez petites, cela ne vous apportera peut-être pas grand-chose, mais cela peut certainement aider à réduire les à-coups lors du chargement différé d'images volumineuses et de leur insertion dans le DOM.

Lorsque les éléments ne se chargent pas

Il arrive que des ressources multimédias ne se chargent pas pour une raison ou une autre, et que des erreurs se produisent. Quand ? Cela dépend, mais voici un scénario hypothétique pour vous: vous disposez d'une règle de mise en cache HTML pour une courte période (par exemple, cinq minutes) et l'utilisateur visite le site ou un utilisateur a laissé un onglet non actualisé ouvert pendant une longue période (plusieurs heures, par exemple) et revient lire votre contenu. Un redéploiement a lieu à un moment donné de ce processus. Au cours de ce déploiement, le nom d'une ressource d'image change en raison de la gestion des versions basée sur le hachage, ou est complètement supprimé. Au moment où l'utilisateur charge l'image en différé, la ressource devient indisponible et échoue.

Bien qu'il s'agisse d'occurrences relativement rares, il peut être nécessaire de disposer d'un plan de sauvegarde en cas d'échec du chargement différé. Pour les images, cette solution peut se présenter comme suit:

var newImage = new Image();
newImage.src = "my-awesome-image.jpg";

newImage.onerror = function(){
  // Decide what to do on error
};
newImage.onload = function(){
  // Load the image
};

En cas d'erreur, la procédure à suivre dépend de votre application. Par exemple, vous pouvez remplacer la zone d'espace réservé de l'image par un bouton permettant à l'utilisateur d'essayer de charger à nouveau l'image, ou simplement afficher un message d'erreur dans cette zone.

D'autres scénarios peuvent également se présenter. Quoi que vous fassiez, ce n'est jamais une mauvaise idée de signaler à l'utilisateur qu'une erreur s'est produite et de lui proposer éventuellement une action à effectuer en cas de problème.

Disponibilité de JavaScript

Ne partez pas du principe que JavaScript est toujours disponible. Si vous comptez charger des images en différé, pensez à proposer le balisage <noscript> qui permettra d'afficher les images si JavaScript n'est pas disponible. L'exemple de remplacement le plus simple consiste à utiliser les éléments <noscript> pour diffuser des images si JavaScript est désactivé:

Je suis une image !

Si JavaScript est désactivé, les utilisateurs voient à la fois l'image d'espace réservé et l'image contenue avec les éléments <noscript>. Pour contourner ce problème, placez une classe no-js sur la balise <html> comme suit:

<html class="no-js">

Placez ensuite une ligne de script intégré dans <head> avant que des feuilles de style ne soient demandées via des balises <link> qui suppriment la classe no-js de l'élément <html> si JavaScript est activé:

<script>document.documentElement.classList.remove("no-js");</script>

Enfin, utilisez du code CSS pour masquer des éléments avec une classe différée lorsque JavaScript n'est pas disponible:

.no-js .lazy {
  display: none;
}

Cela n'empêche pas le chargement des images d'espace réservé, mais le résultat est plus souhaitable. Les personnes pour lesquelles JavaScript est désactivé obtiennent autre chose que des images d'espace réservé, ce qui est préférable aux espaces réservés et à l'absence de contenu d'image pertinent.