Signatur
Beschreibung
Die Eigenschaft root eines IntersectionObserver gibt an, gegen welchen Bereich die Sichtbarkeit der beobachteten Zielelemente berechnet wird. Der Wert entspricht der Option root, die beim Erzeugen des Observers im Konstruktor übergeben wurde. Die Eigenschaft ist nur lesbar. Um den Root zu ändern, muss man einen neuen Observer erzeugen.
Ist root gleich null, spricht man von einem impliziten Root: Berechnet wird dann gegen den Viewport des obersten Dokuments. Das ist der häufigste Fall, etwa beim Lazy Loading von Bildern oder bei Scroll-Animationen. Wird dagegen ein Element angegeben, z. B. ein scrollbarer Container, zählt nur dessen Clip-Bereich (Inhaltsbereich abzüglich Scrollbalken), erweitert oder verkleinert um rootMargin.
Seit einer Erweiterung der Spezifikation darf root auch ein Document sein. Das ist vor allem in iframes nützlich: Übergibt man dort das eigene document, wird gegen den Viewport des iframes statt gegen den des obersten Fensters gemessen. Zudem darf rootMargin dann auch bei ursprungsübergreifenden (cross-origin) iframes angewendet werden.
In der Praxis liest man root vor allem aus, wenn ein Observer in mehreren Kontexten wiederverwendet wird oder wenn man in Debug- und Hilfsfunktionen herausfinden will, auf welchen Container sich die gemeldeten rootBounds beziehen.
Rückgabewert
null, wenn der Viewport des obersten Dokuments verwendet wird.Beispiele
Impliziter Root (Browser-Viewport)
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) console.log('Sichtbar:', entry.target.id);
});
});
console.log(observer.root); // kein root übergeben
console.log(observer.root === null ? 'Viewport des Top-Level-Dokuments' : 'eigener Root');
Scroll-Container als Root für Lazy Loading
const container = document.querySelector('#galerie');
const lazyObserver = new IntersectionObserver((entries, obs) => {
entries.forEach((entry) => {
if (!entry.isIntersecting) return;
const img = entry.target;
img.src = img.dataset.src;
obs.unobserve(img);
});
}, { root: container, rootMargin: '200px 0px' });
container.querySelectorAll('img[data-src]').forEach((img) => lazyObserver.observe(img));
console.log(lazyObserver.root === container);
console.log(lazyObserver.root.id);
Document als Root innerhalb eines iframes
// Läuft im iframe: gegen den Viewport des iframes messen
const observer = new IntersectionObserver((entries) => {
entries.forEach((e) => console.log(e.target.id, e.intersectionRatio.toFixed(2)));
}, { root: document, rootMargin: '50px' });
console.log(observer.root instanceof Document);
observer.observe(document.querySelector('#banner'));
Root in einer Hilfsfunktion auswerten
const describeRoot = (observer) => {
const { root } = observer;
if (root === null) return 'Viewport';
if (root instanceof Document) return 'Dokument';
return `Element <${root.tagName.toLowerCase()}${root.id ? '#' + root.id : ''}>`;
};
const list = document.createElement('div');
list.id = 'liste';
document.body.append(list);
console.log(describeRoot(new IntersectionObserver(() => {})));
console.log(describeRoot(new IntersectionObserver(() => {}, { root: list })));
// Wichtig · Fallstricke
- Nur lesbar: Eine Zuweisung wie
observer.root = elwird ignoriert bzw. wirft im Strict Mode einenTypeError. Um den Root zu wechseln, erzeugt man einen neuen Observer. - Zielelemente müssen Nachfahren sein: Ist
rootein Element, werden nur Ziele korrekt ausgewertet, die im DOM-Baum unterhalb dieses Elements liegen. Andernfalls istisIntersectingimmerfalse. - Overflow erforderlich: Ein Element-Root schneidet nur dann sinnvoll ab, wenn es einen eigenen Clip-Bereich hat (z. B.
overflow: autooderhidden). Ohne Clipping verhält es sich oft anders als erwartet. - Document als Root wird erst seit Chrome/Edge 81, Firefox 76 und Safari 14.1 unterstützt. Ältere Browser werfen beim Konstruktor einen
TypeError.nullund Elemente funktionieren überall. - Bei implizitem Root in cross-origin iframes ist
entry.rootBoundsaus Datenschutzgründennull, undrootMarginwird ignoriert. - Der Observer hält eine Referenz auf den Root. Wird der Container entfernt, sollte man
disconnect()aufrufen, damit keine Speicherlecks entstehen.