Bonnes pratiques concernant le chargement différé

Bien que les images et les vidéos au 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. En tant que tel, il est important de garder à l'esprit les préoccupations suivantes.

Attention au pli

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 éléments 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 les scripts sont terminés et commencent à s'exécuter. Pour les images en dessous de la ligne de flottaison, ce n'est pas un problème. Toutefois, 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 soient affichées dès que possible.

Bien sûr, l'emplacement du pli n'est pas très clair de nos jours, lorsque les sites Web sont consultés sur autant d'écrans de tailles différentes. La partie au-dessus de la ligne de flottaison sur un ordinateur portable peut bien se trouver en dessous sur les appareils mobiles. Il n'y a pas de conseil à 100 % pour résoudre ce problème de manière optimale dans chaque situation. Vous devez effectuer un inventaire des éléments critiques de votre page et charger ces images normalement.

En outre, il n'est pas souhaitable d'être si strict sur la ligne de pliage que le seuil de déclenchement du chargement différé. Pour vos besoins, il peut être plus judicieux d'établir une zone tampon située en dessous de la ligne de flottaison, afin que les images commencent à se charger bien avant que l'utilisateur ne 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 aux valeurs 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 elle peut être remplacée par un élément spécifique à l'aide de la propriété root) est élargie de 256 pixels. Cela signifie que la fonction de rappel s'exécute lorsqu'un élément d'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 le voie réellement.

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

Changement 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 les espaces réservés ne sont pas utilisés. 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. Au minimum, envisagez d'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 donnent une indication sur 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 de l'image finale. Utilisez l'attribut poster dans un élément <video> pour pointer vers une image d'espace réservé. Utilisez également les attributs width et height au niveau des balises <img> et <video>. Cela garantit que la transition des espaces réservés aux images finales ne modifiera pas la taille d'affichage 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épose dans le DOM peuvent lier le thread principal et empêcher l'interface utilisateur de répondre pendant une courte période lors du décodage. Décoder les images de manière asynchrone à l'aide de la méthode decode avant de les insérer dans le DOM peut réduire ce type d'à-coups, mais attention: cette fonctionnalité n'est pas encore disponible partout et ajoute de la complexité à la logique de chargement différé. Si vous souhaitez l'utiliser, vous devez vérifier. Voici comment utiliser Image.decode() avec une création de 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 un code semblable à cet exemple en action. Si la plupart de vos images sont assez petites, cela ne vous servira peut-être pas grand-chose, mais cela peut certainement vous aider à réduire les à-coups lorsque vous chargez de grandes images de manière différée et que vous les insérez dans le DOM.

Lorsque les éléments ne se chargent pas

Il arrive que les ressources multimédias ne se chargent pas pour une raison ou une autre, et que des erreurs se produisent. Quand cela peut-il se produire ? Cela dépend, mais voici un scénario hypothétique pour vous: vous avez 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 obsolète ouvert pendant une longue période (par exemple, plusieurs heures) et revient pour 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 d'une gestion des versions basée sur le hachage ou est complètement supprimé. Au moment où l'utilisateur effectue le chargement différé de l'image, la ressource devient indisponible et échoue.

Bien que ces occurrences soient relativement rares, il peut être judicieux 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
};

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

D'autres scénarios peuvent également survenir. Quoi que vous fassiez, ce n'est jamais une mauvaise idée de signaler à l'utilisateur qu'une erreur s'est produite, et éventuellement de lui donner une mesure à prendre en cas de dysfonctionnement.

Disponibilité de JavaScript

Ne partez pas du principe que JavaScript est toujours disponible. Si vous effectuez le chargement différé des images, envisagez de proposer un balisage <noscript> permettant d'afficher les images au cas où JavaScript ne serait pas disponible. L'exemple de remplacement le plus simple possible consiste à utiliser des éléments <noscript> pour diffuser des images si JavaScript est désactivé:

Je suis une image !

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

<html class="no-js">

Placez ensuite une ligne de script intégré dans <head> avant que toute feuille de style ne soit demandée 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 les éléments avec une classe de latence 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 bien plus que des images d'espace réservé, ce qui est préférable aux espaces réservés et aucun contenu d'image pertinent.