Signatur
Beschreibung
Mit observe() legst du fest, welches Element ein IntersectionObserver überwachen soll. Ein Observer kann beliebig viele Ziel-Elemente gleichzeitig beobachten. Ändert sich das Verhältnis, in dem sich ein Ziel mit dem Root-Element (standardmäßig dem Viewport) überschneidet, und wird dabei einer der konfigurierten threshold-Werte überschritten, ruft der Browser den Callback mit einem IntersectionObserverEntry für dieses Element auf.
Typische Einsatzfälle sind Lazy Loading von Bildern und Komponenten, Infinite Scrolling, das Auslösen von Einblend-Animationen, das Messen von Sichtbarkeit (z. B. für Werbe-Impressions) oder das Hervorheben des aktuell sichtbaren Abschnitts in einem Inhaltsverzeichnis.
Wichtig: Direkt nach dem Aufruf von observe() liefert der Observer asynchron einen ersten Eintrag mit dem aktuellen Zustand des Elements – auch wenn es gar nicht sichtbar ist (dann mit isIntersecting === false). Dein Callback sollte daher immer entry.isIntersecting bzw. entry.intersectionRatio prüfen. Wird ein bereits beobachtetes Element erneut übergeben, passiert nichts.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $target Pflicht | Element | Das zu beobachtende Element. Ist ein root gesetzt, muss target ein Nachfahre dieses Root-Elements sein, damit Schnittmengen erkannt werden. |
Beispiele
Lazy Loading von Bildern
// <img data-src="bild.jpg" class="lazy" alt="...">
const observer = new IntersectionObserver((entries, obs) => {
entries.forEach((entry) => {
if (!entry.isIntersecting) return;
const img = entry.target;
img.src = img.dataset.src;
img.classList.remove('lazy');
obs.unobserve(img); // nur einmal laden
});
}, { rootMargin: '200px 0px' });
document.querySelectorAll('img.lazy').forEach((img) => observer.observe(img));
Einblend-Animation beim Scrollen
const revealObserver = new IntersectionObserver((entries) => {
for (const entry of entries) {
entry.target.classList.toggle('sichtbar', entry.isIntersecting);
console.log(entry.target.id, entry.isIntersecting, entry.intersectionRatio.toFixed(2));
}
}, { threshold: [0, 0.5, 1] });
document.querySelectorAll('section').forEach((section) => revealObserver.observe(section));
Infinite Scrolling mit Sentinel-Element
const liste = document.querySelector('#liste');
const sentinel = document.querySelector('#sentinel');
let seite = 1;
let laedt = false;
const ladeMehr = async () => {
laedt = true;
const res = await fetch(`/api/artikel?seite=${seite++}`);
const artikel = await res.json();
for (const a of artikel) {
const li = document.createElement('li');
li.textContent = a.titel;
liste.append(li);
}
if (artikel.length === 0) scrollObserver.disconnect();
laedt = false;
};
const scrollObserver = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting && !laedt) ladeMehr();
});
scrollObserver.observe(sentinel);
// Wichtig · Fallstricke
- Erster Callback sofort: Nach
observe()wird der Callback für jedes Ziel einmal mit dem Ausgangszustand aufgerufen – auch bei nicht sichtbaren Elementen. ImmerisIntersectingprüfen. - Kein Element: Wird kein
Elementübergeben (z. B.nullaus einem fehlgeschlagenenquerySelector), wirft der Aufruf einenTypeError. - Root-Beziehung: Ist
targetkein Nachfahre des konfiguriertenroot, liefert der Observer nie eine Schnittmenge. - Aufräumen: Beobachtete Elemente mit
unobserve()abmelden bzw. den Observer mitdisconnect()beenden (z. B. beim Entfernen einer Komponente), um unnötige Arbeit und Speicherlecks zu vermeiden. - Performance: Einen Observer für viele Elemente wiederzuverwenden ist günstiger, als pro Element einen eigenen zu erzeugen.
- Kompatibilität: In allen modernen Browsern verfügbar (Chrome 51+, Firefox 55+, Safari 12.1+, Edge 15+). Für native Bild-Lazy-Loading reicht oft auch
loading=\"lazy\".