Mit IntersectionObservers können Sie feststellen, wann ein beobachtetes Element den Darstellungsbereich des Browsers betritt oder verlässt.
Angenommen, Sie möchten erfassen, wann ein Element in Ihrem DOM in den sichtbaren Darstellungsbereich gelangt. Das kann beispielsweise sinnvoll sein, wenn Sie Bilder genau dann laden möchten, wenn sie benötigt werden, oder wenn Sie wissen möchten, ob sich der Nutzer ein bestimmtes Anzeigenbanner ansieht. Dazu können Sie das Scroll-Ereignis verknüpfen oder einen periodischen Timer verwenden und getBoundingClientRect()
auf dieses Element anwenden.
Dieser Ansatz ist jedoch sehr langsam, da jeder Aufruf von getBoundingClientRect()
den Browser dazu zwingt, das gesamte Layout der Seite neu zu erstellen. Außerdem führt er zu erheblichen Rucklern auf Ihrer Website. Es wird fast unmöglich, wenn Sie wissen, dass Ihre Website in einem Iframe geladen wird, und wissen möchten, wann der Nutzer ein Element sehen kann. Aufgrund des Modells mit einer einzigen Quelle und des Browsers können Sie nicht auf Daten von der Webseite zugreifen, die den iframe enthält. Das ist beispielsweise ein häufiges Problem bei Anzeigen, die häufig über Iframes geladen werden.
IntersectionObserver
wurde entwickelt, um diesen Sichtbarkeitstest effizienter zu gestalten. Er ist in allen modernen Browsern verfügbar. IntersectionObserver
gibt Aufschluss darüber, wann ein beobachtetes Element in den Browser-Viewport eintritt oder ihn verlässt.
IntersectionObserver
erstellen
Die API ist recht klein und lässt sich am besten anhand eines Beispiels beschreiben:
const io = new IntersectionObserver(entries => {
console.log(entries);
}, {
/* Using default options. Details below */
});
// Start observing an element
io.observe(element);
// Stop observing an element
// io.unobserve(element);
// Disable entire IntersectionObserver
// io.disconnect();
Wenn Sie die Standardoptionen für IntersectionObserver
verwenden, wird Ihr Rückruf sowohl aufgerufen, wenn das Element teilweise sichtbar wird, als auch wenn es den Darstellungsbereich vollständig verlässt.
Wenn Sie mehrere Elemente beobachten müssen, ist es möglich und empfehlenswert, mehrere Elemente mit der gleichen IntersectionObserver
-Instanz zu beobachten, indem Sie observe()
mehrmals aufrufen.
An Ihren Callback wird ein entries
-Parameter übergeben, der ein Array von IntersectionObserverEntry
-Objekten ist. Jedes solche Objekt enthält aktualisierte Daten zu Überschneidungen für eines Ihrer beobachteten Elemente.
🔽[IntersectionObserverEntry]
time: 3893.92
🔽rootBounds: ClientRect
bottom: 920
height: 1024
left: 0
right: 1024
top: 0
width: 920
🔽boundingClientRect: ClientRect
// ...
🔽intersectionRect: ClientRect
// ...
intersectionRatio: 0.54
🔽target: div#observee
// ...
rootBounds
ist das Ergebnis des Aufrufs von getBoundingClientRect()
auf das Stammelement, das standardmäßig der Darstellungsbereich ist. boundingClientRect
ist das Ergebnis von getBoundingClientRect()
, das auf das beobachtete Element angewendet wird. intersectionRect
ist die Schnittmenge dieser beiden Rechtecke und gibt an, welcher Teil des beobachteten Elements sichtbar ist. intersectionRatio
ist eng damit verwandt und gibt an, wie viel des Elements sichtbar ist. Mit diesen Informationen können Sie jetzt Funktionen wie das Just-in-Time-Laden von Assets implementieren, bevor sie auf dem Bildschirm sichtbar werden. effizient:
IntersectionObserver
s liefern ihre Daten asynchron und Ihr Callback-Code wird im Hauptthread ausgeführt. Außerdem heißt es in der Spezifikation, dass IntersectionObserver
-Implementierungen requestIdleCallback()
verwenden sollten. Das bedeutet, dass der Aufruf Ihres bereitgestellten Rückrufs eine niedrige Priorität hat und vom Browser während der Inaktivität ausgeführt wird. Das ist eine bewusste Designentscheidung.
Scrollende Divs
Ich bin kein großer Fan von Scrollen innerhalb eines Elements, aber ich bin nicht hier, um zu urteilen, und das ist auch IntersectionObserver
nicht. Das Objekt options
hat die Option root
, mit der Sie eine Alternative zum Viewport als Wurzel definieren können. Beachten Sie, dass root
ein Vorfahr aller beobachteten Elemente sein muss.
Alle Daten zusammenführen
Nein! Schlechter Entwickler! Das ist keine sinnvolle Nutzung der CPU-Zyklen Ihrer Nutzer. Denken wir zum Beispiel an einen endlosen Scroller: In diesem Szenario ist es definitiv ratsam, dem DOM Sentinels hinzuzufügen und diese zu beobachten (und wiederzuverwenden). Sie sollten einen Sentinel nahe dem letzten Element im endlosen Scroller hinzufügen. Wenn dieser Sentinel in Sicht kommt, kannst du mit dem Rückruf Daten laden, die nächsten Elemente erstellen, sie an das DOM anhängen und den Sentinel entsprechend neu positionieren. Wenn Sie den Sentinel ordnungsgemäß wiederverwenden, ist kein zusätzlicher Aufruf von observe()
erforderlich. Die IntersectionObserver
funktioniert weiter.
Mehr Updates
Wie bereits erwähnt, wird der Rückruf einmal ausgelöst, wenn das beobachtete Element teilweise sichtbar wird, und noch einmal, wenn es den Darstellungsbereich verlässt. So erhalten Sie mit IntersectionObserver
eine Antwort auf die Frage: „Ist Element X im Blickfeld?“ In einigen Anwendungsfällen reicht das jedoch möglicherweise nicht aus.
Hier kommt die Option threshold
ins Spiel. Sie können damit eine Reihe von intersectionRatio
-Grenzwerten definieren. Ihr Callback wird jedes Mal aufgerufen, wenn intersectionRatio
einen dieser Werte überschreitet. Der Standardwert für threshold
ist [0]
, was das Standardverhalten erklärt. Wenn wir threshold
in [0, 0.25, 0.5, 0.75, 1]
ändern, werden wir jedes Mal benachrichtigt, wenn ein weiteres Viertel des Elements sichtbar wird:
Gibt es noch andere Optionen?
Derzeit gibt es nur eine zusätzliche Option zu den oben aufgeführten. Mit rootMargin
können Sie die Ränder für den Stamm angeben und so den Bereich für Überschneidungen vergrößern oder verkleinern. Diese Ränder werden mit einem CSS-String wie "10px 20px 30px 40px"
angegeben, wobei jeweils der obere, rechte, untere und linke Rand angegeben wird. Zusammenfassend bietet das Options-Objekt IntersectionObserver
folgende Optionen:
new IntersectionObserver(entries => {/* … */}, {
// The root to use for intersection.
// If not provided, use the top-level document's viewport.
root: null,
// Same as margin, can be 1, 2, 3 or 4 components, possibly negative lengths.
// If an explicit root element is specified, components may be percentages of the
// root element size. If no explicit root element is specified, using a
// percentage is an error.
rootMargin: "0px",
// Threshold(s) at which to trigger callback, specified as a ratio, or list of
// ratios, of (visible area / total area) of the observed element (hence all
// entries must be in the range [0, 1]). Callback will be invoked when the
// visible ratio of the observed element crosses a threshold in the list.
threshold: [0],
});
<iframe>
magischer Befehl
IntersectionObserver
s wurden speziell für Werbedienste und Widgets in sozialen Netzwerken entwickelt, in denen häufig <iframe>
-Elemente verwendet werden und die davon profitieren könnten, zu wissen, ob sie im Sichtfeld sind. Wenn ein <iframe>
eines seiner Elemente beobachtet, wird der Callback sowohl beim Scrollen des <iframe>
als auch beim Scrollen des Fensters , das das <iframe>
enthält, zum richtigen Zeitpunkt ausgelöst. Im letzteren Fall wird rootBounds
jedoch auf null
gesetzt, um Datenlecks zwischen Ursprüngen zu vermeiden.
Wozu dient IntersectionObserver
Nicht?
Beachte bitte, dass IntersectionObserver
bewusst weder pixelgenau noch mit geringer Latenz ist. Die Verwendung dieser Daten für die Implementierung von Elementen wie scrollabhängigen Animationen ist zum Scheitern verurteilt, da die Daten zum Zeitpunkt der Verwendung streng genommen veraltet sind. In der Erläuterung finden Sie weitere Informationen zu den ursprünglichen Anwendungsfällen für IntersectionObserver
.
Wie viel Arbeit kann ich im Rückruf erledigen?
Kurz und bündig: Wenn der Callback zu lange dauert, kommt es zu Verzögerungen bei der App. Hier gelten alle gängigen Praktiken.
Gehen Sie vor und überschneiden Sie die Elemente.
IntersectionObserver
wird von allen modernen Browsern unterstützt. Bei Bedarf kann in älteren Browsern eine Polyfill verwendet werden, die im Repository des W3C verfügbar ist. Natürlich können Sie mit dieser Polyfill nicht die Leistungsvorteile erzielen, die eine native Implementierung bietet.
Sie können IntersectionObserver
sofort verwenden. Erzählen Sie uns, was Sie herausgefunden haben.