Intersection Observer: déclencher 1 fois¶
L'essentiel en 3 points
- Un
IntersectionObserversurveille des éléments, et appelle votre fonction quand l'un d'eux entre dans l'écran (ou en sort). - Il ne sert pas à animer au défilement (le CSS et GSAP le font), mais à déclencher une action au bon moment : ajouter une classe, lancer un
fetch, démarrer une vidéo. - Pas de librairie : c'est du JavaScript natif, dans tous les navigateurs.
Quand l'utiliser?¶
| Besoin | L'outil |
|---|---|
| Une animation qui suit le défilement | CSS (animation-timeline) ou GSAP (scrub) |
| Une scène épinglée, une séquence | GSAP + ScrollTrigger |
| Une action, une seule fois : charger les données de la dataviz quand le chapitre approche | IntersectionObserver |
| Ajouter une classe quand un élément est visible (la transition est en CSS) | IntersectionObserver |
Dans votre récit, c'est la façon recommandée de lancer le fetch externe de votre dataviz : seulement quand le visiteur arrive au chapitre, pas au chargement de la page.
Le code¶
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (!entry.isIntersecting) return; // pas encore visible
entry.target.classList.add("is-loaded");
// ou : loadWeather(entry.target);
observer.unobserve(entry.target); // une seule fois
});
}, {
threshold: 1, // visible à 100 %
});
document.querySelectorAll(".card").forEach((card) => {
observer.observe(card);
});
Les morceaux :
new IntersectionObserver(fonction, options): la fonction reçoit un tableauentries, une entrée par élément dont la visibilité a changé.entry.isIntersecting:truesi l'élément est dans l'écran.entry.target: l'élément lui-même.observer.unobserve(): on arrête de le surveiller. C'est ce qui fait « une seule fois ».threshold: la part de l'élément qui doit être visible.0(par défaut) : dès le premier pixel.0.5: la moitié.1: l'élément au complet.rootMargin: agrandit ou rétrécit la zone de l'écran."0px 0px -20% 0px": il faut que l'élément monte de 20 % dans l'écran."0px 0px 50% 0px": il se déclenche une demi-hauteur d'écran avant d'entrer (pratique pour charger des données d'avance).
Dans votre récit¶
Dans la démo du Petit Chaperon rouge, le fichier commun js/outils.js contient une petite fonction réutilisable, et le chapitre 5 s'en sert pour charger la météo seulement quand le chapitre approche :
// js/outils.js
export function observerUneFois(element, action, marge = "0px") {
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (!entry.isIntersecting) return;
action(entry.target);
observer.unobserve(entry.target);
});
}, { rootMargin: marge });
observer.observe(element);
}
// js/chapitres/ch-05.js
import { observerUneFois } from "../outils.js";
export function animate(section, chapitre) {
const meteo = section.querySelector(".meteo");
const lieu = chapitre.contenu.lieu;
// Le fetch part une demi-hauteur d'écran AVANT le chapitre
observerUneFois(
meteo,
(el) => afficherMeteo(el, lieu),
"0px 0px 50% 0px"
);
}
Voir la vidéo de la démo du Petit Chaperon rouge
Et avec ScrollTrigger?
ScrollTrigger.create({ trigger, onEnter, once: true }) fait la même chose. Si vous chargez déjà GSAP, les deux conviennent. L'IntersectionObserver a l'avantage de fonctionner sans librairie, et de continuer à fonctionner avec le mouvement réduit (vos données doivent se charger même si rien ne bouge).