Révéler une carte quand elle arrive à l'écran, charger une image au dernier moment, compter les sections réellement lues : trois besoins qui reviennent sur presque toutes les pages longues.
La méthode historique consistait à écouter le défilement et à mesurer des positions à chaque pixel parcouru. Coûteuse, imprécise, et responsable de bien des saccades. Le navigateur sait faire ce calcul lui-même.
Définition
IntersectionObserver surveille le croisement entre un élément et une zone de référence, la fenêtre par défaut. Il appelle une fonction de rappel quand cet élément entre dans la zone ou en sort, sans qu'aucun écouteur de défilement soit nécessaire.
const observateur = new IntersectionObserver((entrees) => {
for (const entree of entrees) {
if (entree.isIntersecting) {
entree.target.classList.add("visible");
observateur.unobserve(entree.target);
}
}
}, { threshold: 0.25 });
document.querySelectorAll(".carte").forEach((carte) => {
observateur.observe(carte);
});Un seul observateur suit autant d'éléments qu'on lui en confie. L'appel à unobserve retire la carte de la surveillance une fois révélée : une animation d'apparition n'a pas à se rejouer.
Les trois options
Le second argument du constructeur règle la sensibilité. Le tableau décrit ses trois options sur trois colonnes : l'option, sa valeur par défaut, et ce qu'elle commande.
| Option | Par défaut | Ce qu'elle règle |
|---|---|---|
root | null | La zone de référence. Vide, c'est la fenêtre du navigateur |
rootMargin | "0px" | Une marge qui agrandit ou rétrécit cette zone |
threshold | 0 | La part visible de l'élément qui déclenche l'appel |
Une marge de "200px 0px" déclenche l'appel deux cents pixels avant l'arrivée réelle, ce qui laisse à une image le temps de se charger. Un seuil accepte aussi un tableau, [0, 0.5, 1], pour être prévenu à plusieurs paliers.
Ce que contient chaque entrée
La fonction de rappel reçoit un tableau, jamais un élément seul : plusieurs éléments peuvent franchir la limite dans la même image.
- isIntersecting : un Boolean (booléen) qui dit si l'élément croise la zone.
- target : l'élément concerné, indispensable puisque le tableau en mélange plusieurs.
- intersectionRatio : la part visible, de 0 à 1.
- boundingClientRect : les dimensions mesurées, déjà calculées par le navigateur.
Les seuils se comparent à la surface visible, pas à la hauteur. Un élément plus grand que la fenêtre n'atteindra jamais un seuil de 1, et l'appel attendu ne viendra pas.
Questions fréquentes
Pourquoi la fonction se déclenche-t-elle dès le chargement ?
Parce que l'observateur signale l'état initial de chaque élément qu'on lui confie, y compris ceux qui sont hors de l'écran. Ces premiers appels portent un isIntersecting à faux, d'où l'importance de tester cette propriété plutôt que de supposer qu'un appel signifie une entrée à l'écran.
Faut-il encore s'en servir pour charger les images ?
Plus vraiment : l'attribut loading="lazy" couvre le cas des images et des cadres intégrés, en une ligne de HTML et sans script. L'observateur garde tout son intérêt pour les animations d'apparition, le défilement infini et la mesure des sections réellement vues.
Comment arrêter la surveillance ?
unobserve retire un élément, disconnect arrête tout d'un coup. Le second appel est indispensable quand un composant disparaît de la page : sans lui, l'observateur garde une référence vers des éléments retirés, qui ne peuvent plus être libérés de la mémoire.