Intersection Observer

Quand un document web contient beaucoup de ressources (images, vidéos, ...), on évite de tout charger d'un coup et on fait du « lazy loading », du chargement uniquement quand c'est nécessaire, le plus souvent quand la dite ressource arrive dans le viewport du navigateur via le scroll utilisateur. Une nouvelle API facilite grandement le procédé : l'Intersection Observer API.

Bon, pas si nouvelle que ça puisqu'elle est implémentée par les navigateurs modernes depuis un peu plus de deux ans mais je viens de tomber dessus au boulot cet après-midi.

La méthode ancestrale consistait à écouter les événements de scroll, vérifier qu'une ressource déterminée entrait ou non dans le viewport du navigateur et, si c'était le cas, déclencher les traitements adéquats. Rien de bien forcément compliqué mais les évenements comme le scroll ou le resize ont toujours été délicat à manipuler vu qu'ils sont émis assez régulièrement.

La technique n'est pas obsolète mais nous avons dorénavant une API dédiée à ce use case comme souvent quand ce type de pratiques se généralise. Il s'agit de l'API Intersection Observer qui est simplement un observer dédié à une tâche spécifique : observer l'entrée d'un élément dans le viewport d'un élément ancêtre ou de la fenêtre du navigateur.

const observer = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
        if (entry.isIntersecting) {
            loadImage(entry.target);
            observer.unobserve(entry.target);
        }
    });
}, { 
    rootMargin: '100px',
    treshold: 0.1
});

imagesList.forEach((image) => {
    observer.observe(image);
});
Exemple d'utilisation d'un IntersectionObserver

Je l'ai appliqué à mon module lazyPics qui, comme son nom l'indique, charge les images de la page au fur et à mesure qu'elles arrivent dans le viewport. Environ 1/4 de code en moins mais le plus important c'est la simplification que cela entraîne car il y a moins de méthodes, de variables et surtout moins de dépendances externes : dans ce cas-ci, il s'agissait d'une méthode de debounce classique pour minimiser les écoutes du scroll.

L'unique souci que j'ai jusqu'à maintenant relevé c'est que l'Intersection Observer s'accomode mal avec le scroll-behavior à smooth : En haut d'un page avec 20 images et vous cliquez sur un lien qui vous amène à la dernière, les 19 images qui précédent auront été signalées comme entrée dans le viewport.