IntersectionObserver kommt in Sicht

Mit IntersectionObservers können Sie feststellen, wann ein beobachtetes Element in den Darstellungsbereich des Browsers eintritt oder ihn verlässt.

Browser Support

  • Chrome: 51.
  • Edge: 15.
  • Firefox: 55.
  • Safari: 12.1.

Source

Angenommen, Sie möchten erfassen, wann ein Element in Ihrem DOM in den sichtbaren Darstellungsbereich gelangt. Das kann sinnvoll sein, wenn Sie Bilder erst dann laden möchten, wenn sie benötigt werden, oder wenn Sie wissen müssen, ob sich der Nutzer tatsächlich ein bestimmtes Werbebanner ansieht. Dazu können Sie das Scroll-Ereignis verknüpfen oder einen periodischen Timer verwenden und getBoundingClientRect() für dieses Element aufrufen.

Dieser Ansatz ist jedoch sehr langsam, da jeder Aufruf von getBoundingClientRect() den Browser dazu zwingt, das Layout der gesamten Seite neu zu erstellen. Das führt zu erheblichen Verzögerungen auf Ihrer Website. Noch schwieriger wird es, wenn Sie wissen, dass Ihre Website in einem iFrame geladen wird, und Sie wissen möchten, wann der Nutzer ein Element sehen kann. Das Single-Origin-Modell und der Browser verhindern, dass Sie auf Daten von der Webseite zugreifen, die den iFrame enthält. Dies ist ein häufiges Problem bei Anzeigen, die oft über iFrames geladen werden.

IntersectionObserver wurde entwickelt, um diesen Sichtbarkeitstest effizienter zu machen, und ist in allen modernen Browsern verfügbar. IntersectionObserver informiert Sie, wenn ein beobachtetes Element in den Darstellungsbereich des Browsers eintritt oder ihn verlässt.

iFrame-Sichtbarkeit

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 der Callback 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 ratsam, mehrere Elemente mit derselben IntersectionObserver-Instanz zu beobachten, indem Sie observe() mehrmals aufrufen.

An den Callback wird ein entries-Parameter übergeben, der ein Array von IntersectionObserverEntry-Objekten ist. Jedes dieser Objekte enthält aktualisierte Kreuzungsdaten 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() für das Stammelement, das standardmäßig der Darstellungsbereich ist. boundingClientRect ist das Ergebnis von getBoundingClientRect(), das für das beobachtete Element aufgerufen 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 Funktionen wie das Just-in-Time-Laden von Assets implementieren, bevor sie auf dem Bildschirm sichtbar werden. Effizient.

Schnittverhältnis.

IntersectionObservers 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 des von Ihnen bereitgestellten Callbacks eine niedrige Priorität hat und vom Browser während der Inaktivität ausgeführt wird. Dies ist eine bewusste Designentscheidung.

Scrollbare Div-Elemente

Ich bin kein großer Fan davon, innerhalb eines Elements zu scrollen, aber ich bin nicht hier, um zu urteilen, und IntersectionObserver auch nicht. Das Objekt options akzeptiert die Option root, mit der Sie eine Alternative zum Darstellungsbereich als Stamm definieren können. Dabei ist zu beachten, dass root ein Ancestor aller beobachteten Elemente sein muss.

Alles Mögliche schneiden.

Nein! Böser Entwickler! Das ist keine rücksichtsvolle Nutzung der CPU-Zyklen Ihrer Nutzer. Sehen wir uns als Beispiel einen Infinite Scroller an: In diesem Szenario ist es auf jeden Fall ratsam, dem DOM Sentinel-Elemente hinzuzufügen und diese zu beobachten (und wiederzuverwenden). Sie sollten einen Sentinel in der Nähe des letzten Elements im Infinite Scroller hinzufügen. Wenn dieser Sentinel sichtbar wird, können Sie den Callback verwenden, um Daten zu laden, die nächsten Elemente zu erstellen, sie an das DOM anzuhängen und den Sentinel entsprechend neu zu positionieren. Wenn Sie den Sentinel ordnungsgemäß recyceln, ist kein zusätzlicher Aufruf von observe() erforderlich. IntersectionObserver funktioniert weiterhin.

Unendliches Scrollen

Mehr Updates, bitte

Wie bereits erwähnt, wird der Callback einmal ausgelöst, wenn das beobachtete Element teilweise sichtbar wird, und ein weiteres Mal, wenn es den Darstellungsbereich verlassen hat. So erhalten Sie von IntersectionObserver eine Antwort auf die Frage „Ist Element X sichtbar?“. In einigen Anwendungsfällen reicht das jedoch möglicherweise nicht aus.

Hier kommt die Option threshold ins Spiel. Sie können damit ein Array von intersectionRatio-Schwellenwerten 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:

Animation des Schwellenwerts.

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 das Stammelement angeben und so den für Schnittpunkte verwendeten Bereich vergrößern oder verkleinern. Diese Ränder werden mit einem String im CSS-Stil angegeben, z. B. "10px 20px 30px 40px", wobei der obere, rechte, untere und linke Rand angegeben wird. Zusammenfassend bietet die IntersectionObserver-Optionsstruktur die folgenden 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> Magie

IntersectionObservers wurden speziell für Werbedienste und Widgets für soziale Netzwerke entwickelt, die häufig <iframe>-Elemente verwenden und davon profitieren könnten, wenn sie wissen, ob sie sichtbar 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, zu den entsprechenden Zeiten ausgelöst. Im letzteren Fall wird rootBounds jedoch auf null gesetzt, um zu verhindern, dass Daten ursprungsübergreifend weitergegeben werden.

Worum geht es bei IntersectionObserver nicht?

Beachten Sie, dass IntersectionObserver absichtlich weder pixelgenau noch mit niedriger Latenz ist. Wenn Sie sie für die Implementierung von scrollabhängigen Animationen verwenden, wird das wahrscheinlich nicht funktionieren, da die Daten streng genommen veraltet sind, wenn Sie sie verwenden. In der Erläuterung finden Sie weitere Informationen zu den ursprünglichen Anwendungsfällen für IntersectionObserver.

Wie viel Arbeit kann ich im Callback erledigen?

Kurz und bündig: Wenn du zu viel Zeit im Callback verbringst, wird deine App langsamer. Es gelten alle gängigen Best Practices.

Elemente schneiden

Die Browserunterstützung für IntersectionObserver ist gut, da es in allen modernen Browsern verfügbar ist. Falls erforderlich, kann in älteren Browsern ein Polyfill verwendet werden. Dieses ist im WICG-Repository verfügbar. Natürlich bietet dieses Polyfill nicht die Leistungsvorteile einer nativen Implementierung.

Sie können IntersectionObserver sofort verwenden. Erzählen Sie uns, was Sie sich ausgedacht haben.