IntersectionObserver
Observe si un élément est visible dans la fenêtre ou dans un conteneur défilant, et appelle une fonction quand cela change.
- Renvoie
- Un nouvel objet
IntersectionObserver.
Exemple
#const feed = document.querySelector('#feed')
const lessons = feed.querySelectorAll('p')
const observer = new IntersectionObserver((entries) => {
for (const entry of entries) {
const state = entry.isIntersecting ? 'visible' : 'cachée'
console.log(`${entry.target.textContent}: ${state}`)
}
}, { root: feed })
lessons.forEach((lesson) => observer.observe(lesson))
console.log(`J’observe ${lessons.length} leçons`)La première entrée vient du code synchrone, et l’état des leçons arrive plus tard, dans la fonction de rappel. « Boucles » n’est que partiellement visible, mais avec le threshold: 0 par défaut, un seul pixel suffit. Faites défiler la liste dans l’aperçu, et la console affichera d’autres changements.
Définition et utilisation
#IntersectionObserver vous informe quand un élément entre dans la zone visible ou en sort. Plutôt que de vérifier la position des éléments à chaque défilement de la page, vous créez un observateur avec une fonction de rappel, et le navigateur l’appelle lui-même au bon moment. C’est la base du chargement différé, des listes infinies, des animations déclenchées au défilement et du comptage des affichages.
La fonction de rappel reçoit un tableau d’objets IntersectionObserverEntry. Les champs les plus importants sont target (l’élément observé), isIntersecting (si l’élément est visible) et intersectionRatio (quelle fraction de l’élément est visible, de 0 à 1). Le premier appel a lieu juste après observe(), donc vous connaissez immédiatement l’état de départ.
Vous passez les options dans le deuxième argument du constructeur. root est l’élément par rapport auquel la visibilité est calculée (la fenêtre du navigateur par défaut). rootMargin agrandit ou réduit cette zone, par exemple "200px" permet de commencer le chargement avant que l’élément apparaisse à l’écran. threshold détermine à partir de quelle fraction visible appeler la fonction, par exemple 0.5 ou [0, 0.5, 1].
La méthode observe() ajoute un élément à l’observation, unobserve() le retire, et disconnect() met fin à toute l’observation. La fonction de rappel s’exécute de façon asynchrone, donc ses entrées dans la console apparaissent après le code synchrone.
Syntaxe
#new IntersectionObserver(callback)
new IntersectionObserver(callback, options)
observer.observe(element)
observer.unobserve(element)
observer.disconnect()Paramètres
#callback
function (entries, observer)
La fonction appelée lors d’un changement de visibilité. Elle reçoit un tableau d’entrées et l’observateur lui-même.options
objet, optionnel
root(un élément, ounullpour la fenêtre),rootMargin(une marge écrite comme en CSS, par ex."0px 0px 200px 0px") etthreshold(un nombre ou un tableau de nombres de 0 à 1).
Plus d’exemples
#const viewport = document.querySelector('#viewport')
const observer = new IntersectionObserver((entries) => {
for (const entry of entries) {
const percent = Math.round(entry.intersectionRatio * 100)
console.log(`${entry.target.textContent}: visible à ${percent} %`)
}
}, { root: viewport, threshold: [0, 0.25, 0.5, 0.75, 1] })
viewport.querySelectorAll('.card').forEach((card) => observer.observe(card))La seconde carte dépasse du conteneur, donc on n’en voit qu’un quart. Faites défiler le conteneur dans l’aperçu, et l’observateur se déclenchera chaque fois que la partie visible franchit l’un des seuils de threshold.
const list = document.querySelector('#list')
const sentinel = document.querySelector('#sentinel')
let page = 0
const observer = new IntersectionObserver(([entry]) => {
if (!entry.isIntersecting) return
page += 1
for (let i = 1; i <= 5; i++) {
const item = document.createElement('li')
item.textContent = `Tâche ${(page - 1) * 5 + i}`
sentinel.before(item)
}
console.log(`Page ${page} chargée`)
if (page === 3) {
observer.disconnect()
sentinel.textContent = 'Ce sont toutes les tâches'
}
}, { root: list })
observer.observe(sentinel)Un élément sentinelle se trouve à la fin de la liste. Quand il devient visible, on ajoute d’autres tâches juste avant lui. Faites défiler la liste jusqu’en bas dans l’aperçu pour charger les pages suivantes. Après la troisième, l’observateur se déconnecte.
const observer = new IntersectionObserver((entries) => {
for (const entry of entries) {
if (!entry.isIntersecting) continue
const img = entry.target
img.src = img.dataset.src
observer.unobserve(img)
}
}, { rootMargin: '200px' })
document.querySelectorAll('img[data-src]').forEach((img) => observer.observe(img))Sans l’option root, la visibilité est calculée par rapport à la fenêtre du navigateur. L’image ne reçoit sa véritable adresse qu’une fois à 200 px de l’écran, puis elle cesse d’être observée. Dans les cas simples, l’attribut HTML loading="lazy" suffit à obtenir le même résultat.
Compatibilité des navigateurs
#Largement disponible · depuis 2019
Fonctionne dans tous les navigateurs modernes, y compris sur mobile. Vous pouvez l’utiliser sans crainte.
- Chrome
- Edge
- Firefox
- Safari
Bonnes pratiques
#- Après une action ponctuelle, comme le chargement d’une image, appelez
observer.unobserve(element). L’observateur ne continuera pas à suivre l’élément pour rien. - Un seul observateur peut suivre plusieurs éléments. Ne créez pas un observateur séparé pour chaque élément d’une liste.
- Pour le simple chargement différé d’images, l’attribut
loading="lazy"en HTML suffit souvent. Utilisez un observateur quand vous avez besoin de votre propre logique.
Entrées associées
#- ResizeObserverAppelle une fonction chaque fois que la taille d’un élément observé change, quelle qu’en soit la cause.
- MutationObserverObserve les changements dans l’arbre du DOM : éléments ajoutés et supprimés, changements d’attributs et de texte, et les signale dans une seule fonction.
- Element.getBoundingClientRect()Renvoie la taille d’un élément et sa position par rapport à la zone visible de la fenêtre, sous la forme d’un objet DOMRect.
- Element.scrollIntoView()Fait défiler la page et les conteneurs défilants pour que l’élément apparaisse à l’écran, par un saut ou en douceur.
- HTMLElement.datasetUn objet avec les valeurs des attributs data-* d’un élément, pour lire et écrire vos propres données.
Vous voyez une erreur ou il manque un exemple ? Écrivez-nous.