Trucsweb.com

Trucsweb.com

Javascript

L’optimisation de la programmation Web

RDFFav

Chargement différé ou paresseux (lazy) des images

Le meilleur truc pour diminuer et optimiser le chargement d’une page, c’est de différer le chargement des grosses images d’une page Web.lazy, picture,PageSpeed Insights,asynchrone,image,paresseux,loading,chargement,refer,différé,IntersectionObserverChargement différé ou paresseux (lazy) des images

Oblomov

Le meilleur truc pour diminuer et optimiser le chargement d’une page, c’est de différer le chargement des grosses images d’une page Web! C’est-à-dire d’attendre que l’image soit dans l’écran avant de la télécharger. Des grosses images, car trop c’est comme pas assez! Exagérer sur le nombre d’images gérées en JavaScript peut tout aussi alourdir le chargement initial de la page...

Les images sont de loin ce qui est le plus lourd dans une page Web et il n’est pas rare d’en rencontrer beaucoup dans une seule page Web. Ce qui ralentit considérablement le chargement de la page, particulièrement avec un téléphone intelligent. C’est aussi ce qui donne la plus grande impression dans une page Web. Avant même d’évaluer le contenu, l’internaute moyen est influencé par la qualité des images. Malgré l’intelligence ou l’adage, l’habit fait malheureusement toujours le moine lorsqu’il est question de la première impression! Le pire, c’est que ces images se retrouvent généralement à l’extérieure de l’écran. C’est donc inutile de les charger avant qu’elles apparaissent!

Au-delà du format d’image, d’une bonne compression ou des images adaptatives, l’idée est de ne pas charger du tout les images et d’attendre après le défilement de la page! En prime, vous obtiendrez un bien meilleur résultat dans le test « Google PageSpeed Insights »!

L’attribut « loading »

Le plus simple est d’utiliser l’attribut native loading, de plus en plus compatible directement dans l’élément <img>.

<img src="image.jpg" alt="Texte alternatif" loading="lazy" />

Et ça fonctionne. Si l’image n’est pas déjà dans la mémoire cache, elle se charge seulement lorsque l’internaute fait défiler la page jusqu’à son emplacement. C’est très facile de tester cette fonctionnalité. Ouvrez la console du navigateur (la touche [F12]). Vous remarquerez qu’il n’y a aucune requête pour charger l’image. Si c’est le cas, c’est que votre navigateur n’est pas compatible ou que l’image est déjà dans la mémoire cache. Pour s’en assurer, ajouter un paramètre au bout de l’adresse de l’image. Exemple: image.jpg?v-1.0.

Son avantage, d’une simplicité infantile. Son désavantage, pas facile d’ajouter une animation lors du chargement.

La « Politique de fonctionnalité » (Feature policy), un peu comme la « Politiques de sécurité du contenu » (Content Security Policies) permet aux développeurs d’activer ou désactivé cette fonctionnalité pour tous les éléments image et iframe de la page. Il semblerait que Google ait malheureusement retiré cette fonctionnalité!

Avec JavaScript

L’avantage avec la méthode JavaScript c’est qu’on peut profiter du chargement différé pour changer et animer l’image, comme un effet de fondu. Pour ma part j’utilise souvent l’excellent [be]Lazy.js par Bjørn Klinggaard (Télécharger la version v1.8.2). Plus simplement, voilà un script de la W3C :

La technique consiste à détecter un des évènements (défilement, changement d’orientation ou changement de dimension de la page) pour appeler la fonction qui ajoute un "timer" pour permettre en temps réel de tester la position de chaque image (avec la classe « lazy ») par rapport à la position de la page (innerHeight+pageYOffset). Si la position de l’image est plus petite que la position de la page, on utilise l’attribut data-src pour définir le src (URL) de l’image tout en supprimant la classe « lazy » (qui ne sert à rien d’autre) question d’éviter de traiter une deuxième fois l’image. Puis on supprime les écouteurs d’évènement.

<!DOCTYPE html>
<html>
  <head>
    <title>Exemple de la W3C</title>
    <style>
      img {
        width: 500px;
        height: 350px;
        display: block;
        margin: 10px auto;
      }
    </style>
  </head>
  <body>
    <img src="https://images.unsplash.com/photo-1482784160316-6eb046863ece?ixlib=rb-1.2.1&auto=format&fit=crop&w=1050&q=80" />
    <img src="https://images.unsplash.com/photo-1488441770602-aed21fc49bd5?ixlib=rb-1.2.1&auto=format&fit=crop&w=1050&q=80" />
    <img src="https://images.unsplash.com/photo-1426604966848-d7adac402bff?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjExMDk0fQ&auto=format&fit=crop&w=1050&q=80" />
    <!-- Par défaut, aucune des images suivante n’est affichée par défaut avec l’attribut « data-src » -->
    <img class="lazy-load" data-src="https://images.unsplash.com/photo-1545105511-839f4a45a030?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1050&q=80" />
    <img class="lazy-load" data-src="https://images.unsplash.com/photo-1493246507139-91e8fad9978e?ixlib=rb-1.2.1&auto=format&fit=crop&w=1050&q=80" />
    <img class="lazy-load" data-src="https://images.unsplash.com/photo-1473800447596-01729482b8eb?ixlib=rb-1.2.1&auto=format&fit=crop&w=1050&q=80" />
    <img class="lazy-load" data-src="https://images.unsplash.com/photo-1491250974528-9443b2902f18?ixlib=rb-1.2.1&auto=format&fit=crop&w=1050&q=80" />
    <img class="lazy-load" data-src="https://images.unsplash.com/photo-1473800447596-01729482b8eb?ixlib=rb-1.2.1&auto=format&fit=crop&w=1050&q=80" />
    <img class="lazy-load" data-src="https://images.unsplash.com/photo-1500993855538-c6a99f437aa7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1050&q=80" />
    <img class="lazy-load" data-src="https://images.unsplash.com/photo-1501018313157-78d10f597133?ixlib=rb-1.2.1&auto=format&fit=crop&w=1055&q=80" />
  
    <!-- Personnellement, j'aime utiliser une image par défaut encodée avec les bonne dimensions -->
    <img class="lazy-load" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" width="200" height="200" data-src="image.jpg" />

    <script>
      document.addEventListener("DOMContentLoaded", function() {
        let lazyloadImages = document.querySelectorAll("img.lazy-load");
        let lazyloadThrottleTimeout;

        function lazyload() {
          if(lazyloadThrottleTimeout) {
            clearTimeout(lazyloadThrottleTimeout);
          }
          lazyloadThrottleTimeout = setTimeout(function() {
            let scrollTop = window.pageYOffset;
            lazyloadImages.forEach(function(img) {
              if(img.offsetTop < (window.innerHeight + scrollTop)) {
                img.src = img.dataset.src;
                img.classList.remove("lazy");
              }
            });
            if(lazyloadImages.length == 0) {
              document.removeEventListener("scroll", lazyload);
              window.removeEventListener("resize", lazyload);
              window.removeEventListener("orientationChange", lazyload);
            }
          }, 20);
        }
        document.addEventListener("scroll", lazyload);
        window.addEventListener("resize", lazyload);
        window.addEventListener("orientationChange", lazyload);
      });
    </script>
  </body>
</html>

Source : « Lazy load images with JavaScript » - W3C

Chargement différé avec l’API « IntersectionObserver »

L’écouteur ou l’observateur d’intersection observer de manière asynchrone l’évolution de l’intersection d’un élément cible avec un élément ancêtre ou avec la zone d’affichage d’un document de niveau supérieur. Il permet de savoir si un élément de la page s’en vient, s’il est arrivé ou s’il est parti sans devoir utiliser un « timer ». Un peu comme un train dans une gare. Il a besoin de deux paramètres, l’appel de fonction (callback) et les options :

  • root - La racine. L’élément ancêtre ou la fenêtre d’affichage que l’élément observé va croiser (la gare).
  • rootMargin - La racine, mais avec une plus grande zone pour surveiller les intersections.
  • threshold - Comme l’option précédente, mais avec un tableau de pourcentage entre 0 et 1,0.
var options = {
  root: document.querySelector("lagare"),
  rootMargin: "0px",
  threshold: 1.0
}

var observateur = new IntersectionObserver(maFonction, options);

Voilà un code rudimentaire qui définie les option (par défaut) et crée une instance de l’API :

<style>
/* Optionnel : permet d'ajouter une animation avec la transparence */
img.lazy-image {
  opacity: 0.1;
  will-change: opacity;
  transition: all 0.3s;
}
img.lazy-image.chergee {
  opacity: 1;
}
</style>

<img id="oImage" class="lazy-image" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" width="200" height="200" data-src="image.jpg" alt="Image" />


<script>
var options = {
  root: null,
  rootMargin: "0px",
  threshold: 1.0
}

var maFonctionIntersection = function(entrees, observateur) {
  // Boucle chaque élément de la cible
  entrees.forEach(entree => {
    
    // Trace qui affiche la valeur « isIntersecting »
    console.log("En intersection : "+ entree.isIntersecting);

    // Si l'élément est en intersection avec la cible
    //   lui donner l'adresse (src) de l'attribut « data-src »
    if(entree.isIntersecting) entree.target.src = entree.target.dataset.src;

    // Optionnel : quand l’image est chargée, ajouter la classe « chergee » pour appliquer l’animation
    entree.target.onload = () => entree.target.classList.add("chergee");

  });
};

// Assure que la page est chargée
window.addEventListener("load", function(event) {
  // Crée l'instance de l'observateur d'intersection
  var observateur = new IntersectionObserver(maFonctionIntersection, options);
  // Crée l'instance de l'image
  var oImage = document.querySelector("#oImage");
  // Transmets la cible à l'observateur
  observateur.observe(oImage);
});
</script>

Il n’y a qu’Internet Explorer qui n’est pas compatible avec L’API IntersectionObserver. Pour plus de détail sur l’API, consultez le texte de « Intersection Observer API. Rahul Nanwani (CSS-Tricks) offre aussi un exemple plus efficace avec l’écouteur « IntersectionObserver ».

Image de fond (background-image)

Ce qui est intéressant avec l’API « IntersectionObserver » c’est qu’il permet aussi de différer le chargement des images de fond, chose impossible avec l’attribut loading="lazy". L’exemple suivant permet aussi de détecter quand le défilement de la page arrive à l’endroit où le conteneur de l’image de fond se situe à l’aide de l’écouteur « IntersectionObserver » pour définir le « url » de l’image de fond. Cette fois en interchangeant la classe CSS « lazy » :


<style>
#bg-image.lazy {
   background-image: none;
   background-color: #F1F1FA;
}
#bg-image {
  background-image: url("image.jpg");
  max-width: 600px;
  height: 400px;
}
</style>

<div id="bg-image" class="lazy"></div>

<script>
document.addEventListener("DOMContentLoaded", function() {
  var lazyloadImages;    

  if ("IntersectionObserver" in window) {
    lazyloadImages = document.querySelectorAll(".lazy");
    var imageObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          var image = entry.target;
          image.classList.remove("lazy");
          imageObserver.unobserve(image);
        }
      });
    });

    lazyloadImages.forEach(function(image) {
      imageObserver.observe(image);
    });
  } else {  
    var lazyloadThrottleTimeout;
    lazyloadImages = document.querySelectorAll(".lazy");
    
    function lazyload () {
      if(lazyloadThrottleTimeout) {
        clearTimeout(lazyloadThrottleTimeout);
      }    

      lazyloadThrottleTimeout = setTimeout(function() {
        var scrollTop = window.pageYOffset;
        lazyloadImages.forEach(function(img) {
            if(img.offsetTop < (window.innerHeight + scrollTop)) {
              img.src = img.dataset.src;
              img.classList.remove("lazy");
            }
        });
        if(lazyloadImages.length == 0) { 
          document.removeEventListener("scroll", lazyload);
          window.removeEventListener("resize", lazyload);
          window.removeEventListener("orientationChange", lazyload);
        }
      }, 20);
    }

    document.addEventListener("scroll", lazyload);
    window.addEventListener("resize", lazyload);
    window.addEventListener("orientationChange", lazyload);
  }
})
</script>

Source : « The Complete Guide to Lazy Loading Images »

Conclusion
Dans la mesure ou l’attribut loading="lazy" est de plus en plus supporté, ces scripts deviennent lourd et inutile. Sinon, comme je disait plus haut, j’utilise souvent l’excellent et très légé script [be]Lazy.js par Bjørn Klinggaard (Télécharger la version v1.8.2). Mais il existe plusieurs llibrairie gratuite :
Références
, Analyste programmeurConception oznogco multimédia (http://oznogco.com), Trucsweb
Dernière mise à jour :

Commentaires

Ajouter un commentaire
Votre adresse de courriel ne sera pas publiée. * L'astérisque indique les champs obligatoires.
Votre évaluation du tutoriel

10/10 sur 1 revues.
       Visites : 127 - Pages vues : 135
X

Trucsweb.com Connexion

Connexion

X

Trucsweb.com Mot de passe perdu

Connexion

X

Trucsweb.com Conditions générales

Conditions

Responsabilité

La responsabilité des Trucsweb.com ne pourra être engagée en cas de faits indépendants de sa volonté. Les informations mises à disposition sur ce site le sont uniquement à titre purement informatif et ne sauraient constituer en aucun cas un conseil ou une recommandation de quelque nature que ce soit.

Aucun contrôle n'est exercé sur les références et ressources externes, l'utilisateur reconnaît que les Trucsweb.com n'assume aucune responsabilité relative à la mise à disposition de ces ressources, et ne peut être tenue responsable quant à leur contenu.

Droit applicable et juridiction compétente

Les règles en matière de droit, applicables aux contenus et aux transmissions de données sur et autour du site, sont déterminées par la loi canadienne. En cas de litige, n'ayant pu faire l'objet d'un accord à l'amiable, seuls les tribunaux canadien sont compétents.

X

Trucsweb.com Trucsweb

X

Trucsweb.com Glossaire

X

Trucsweb.com Trucsweb

X

Trucsweb.com Trucsweb

Conditions

Aucun message!

Merci.

X
Aucun message!
X

Trucsweb.com Créer un compte

Créer un compte

.
@