Lerne Coding
Ist das Element im Viewport? JavaScript Intersection Observer

IntersectionObserver in JavaScript

Inhaltsverzeichnis
[[TABLE OF CONTENTS]]
access_timeGeschätzte Lesezeit ca. Minuten

Der Intersection Observer in JavaScript ist ein noch relative neue Funktion, wenn man bedenkt, dass der Support für Safari erst 2019 kam. In Chrome und Firefox gibt es die Funktion bereits seit 2017. Der IntersectionObserver ist dazu da, um zu erkennen, ob ein HTML Elemente im sichtbaren Bereich des Viewports liegt oder in einem bestimmten Faktor davor oder danach.

IntersectionObserver Verfügbarkeit Weltweit: 96.73%

API that can be used to understand the visibility and position of DOM elements relative to a containing element or to the top-level viewport. The position is delivered asynchronously and is useful for understanding the visibility of elements and implementing pre-loading and deferred loading of DOM content.

Internet Explorer nein
Microsoft Edge 16 +
Firefox 55 +
Google Chrome 58 +
Safari 12.1 +
Opera 45 +
iOS Safari 12.2-12.5 +
Opera Mini nein
Android Webview 122 +
Android Chrome 122 +
Android Firefox 123 +
Samsung Internet 7.2-7.4 +
Daten abgerufen von https:/­/­caniuse.com/­intersectionobserver

Gerade im Bereich von LazyLoading und Animation kann der Observer das Arbeiten vereinfachen, vorher musste mit einem Scroll EventListener die aktuelle Position abgefragt werden. Der neue Observer kann diese Prozesse intern regeln, das, die Arbeit deutlich einfacher macht. Neben einer simplen Abfrage, ob das Element im Viewport ist, kann auch der Prozentwert abgefragt werden, zu wie viel Prozent das Element im View ist. Der Viewport beschreibt den zur Darstellung der Webseite zur Verfügungsstehenden Bereich auf dem Monitor. Alternative kann auch ein eigener Viewport angegeben werden, mittels root.

Neben dem IntersectionObserver gibt es noch 3 weitere Observer, und zwar den MutationObserver, um Änderungen im DOM zu erkennen. Den ReziseObserver, um eine Größen-Veränderung von Elementen zu erkennen. Und zu guter Letzt den PerformanceObserver, um Performance-Messungen zu tracken und auszulesen.

In dem Video von Unleashed Design wird die Verwendung des IntersectionObservers hervorragend auch einmal visuell erklärt.

Die Intersection Observer API

Erklärung des IntersectionObservers

Der IntersectionObserver kann auf jedes beliebiges HTML Element angewendet werden. Über den threshold kann definiert werden bei welchem Prozentwert dieses Reagieren soll. Dort kann auch ein Array von mehreren Werten definiert werden. Sobald der IntersectionObserver ausgelöst wurde, wird die Funktion gefeuert. Diese bekommt ein Array<IntersectionObserverEntry> übergeben, diese hängt davon ab wie viele Elemente gerade darauf registriert sind.

HandleEntriese enthält alle Element die Überprüft werden sollen dort drinnen wird meist ein forEach Loop verwendet. Anschließende können noch weitere Optionen angehangen werden, diese können der nachfolgenden Tabelle entnommen werden.

const observer = new IntersectionObserver (handleEntries, options);
Optionen vom IntersectionObserver

root

Das Elternelement/Viewport in dem das zu Beobachtende Element liegt. Standardmäßig ist der Wert null bedeutet es ist der Viewport des Browsers.

rootMargin

Ein Abstand für den Viewport kann einbezogen werden. Verhält sich wie in CSS Margin, interessant für eine Feiner Abstimmung.

threshold

Eine Array oder ein Wert zwischen 0 und 1 bei diesen wird die Callback Function gefeuert. 0.1 muss das Element nur mit 10% im Viewport sein bei 0.9 müssen es 90% sein.

Über die intersectionRatio kann der Wert zu wie viel Prozent das entsprechende Element im Viewport ist ausgelesen werden - über den threshold können diese Punkte bestimmt werden. So können unterschiedliche Events je nach Prozent wert ausgelöst werden. Diese ist für Animationen, LazyLoading und weitere Elemente interessant.

Das nachfolgende Beispiel zeigt einmal die Ausgabe der Prozentwerte, zu wie viel Prozent die entsprechenden Bereiche im Viewport sind.

const images = document.querySelectorAll('.example-code img');

observer = new IntersectionObserver(generateEntries,{threshold: [...range(0,102),1],root: document.querySelector('div.example-code'),rootMargin:'32px'});

images.forEach(e => {
  observer.observe(e);
})

function generateEntries(entries){
    entries.forEach(setPercantage)
}

function setPercantage(e){
    let percantage = Math.floor(e.intersectionRatio * 100) + " %";

    e.target.previousElementSibling.textContent = percantage;
    e.target.nextElementSibling.textContent = percantage;
}

function range(r,a){return Array.apply(0,Array(a-1)).map((a,n)=>"0."+(n+r))}

Beispiel für die Verwendung vom Intersection Observer

Nach dem wir nun die Details des Intersection Observers kennen gelernt haben schauen wir in einigen Beispielen noch einmal die Funktionalität genauer an.

Der Aufbau der zwei nachfolgenden Beispiele ist immer der Selbe der unterschiedlich liegt in der Function die abgerufen wird, da unterschiedliche Schritte Ausgeführt werden müssen. Das Property e hat immer die Entsprechenden Informationen vom Observer um die Position des Elements bestimmen zu können.

const images = document.querySelectorAll('img');

observer = new IntersectionObserver(generateEntries,{threshold: [...range(0,102),1],root: document.querySelector('div.example-code'),rootMargin:'32px'});

images.forEach(e => {
  observer.observe(e);
})

function generateEntries(entries){
    entries.forEach(setFunction)
}

function setFunction(e){
      console.log(e.intersectionRatio);
}

function range(r,a){return Array.apply(0,Array(a-1)).map((a,n)=>"0."+(n+r))}

LazyLoading von Bildern

Um ein LazyLoading von Bildern mit dem Intersection Observer zu realisieren ist es notwendig das jedes Bild ein Data Attribute hat zum Beispiel data-src ist sehr geläufig. Im Beispiel verwende ich data-img die Wahl des Attributes ist also frei wählbar. Wichtig ist das man den threshold nicht zu niedrige Konfiguriert damit das Bild nicht viel zu früh geladen wird.

<div class="example-code">

  <h1>Intersection Observer - LazyLoading</h1>

  <p>
    Lorem ipsum dolor sit amet, <strong>consetetur sadipscing elitr</strong>, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo
    dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
    <strong>Lorem ipsum</strong> dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, <i>sed diam voluptua</i>. At vero eos et accusam et justo
    duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
  </p>

  <img data-img="https://hellocoding.de/assets/placeholder/pic-3.jpg" alt="Random Picture" />

  <p>
    Lorem ipsum dolor sit amet, <strong>consetetur sadipscing elitr</strong>, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo
    dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
    <strong>Lorem ipsum</strong> dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, <i>sed diam voluptua</i>. At vero eos et accusam et justo
    duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
  </p>

  <img data-img="https://hellocoding.de/assets/placeholder/pic-4.jpg" alt="Random Picture" />

  <p>
    Lorem ipsum dolor sit amet, <strong>consetetur sadipscing elitr</strong>, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo
    dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
    <strong>Lorem ipsum</strong> dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, <i>sed diam voluptua</i>. At vero eos et accusam et justo
    duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
  </p>

  <img data-img="https://hellocoding.de/assets/placeholder/pic-5.jpg" alt="Random Picture" />

  <p>
    Lorem ipsum dolor sit amet, <strong>consetetur sadipscing elitr</strong>, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo
    dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
    <strong>Lorem ipsum</strong> dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, <i>sed diam voluptua</i>. At vero eos et accusam et justo
    duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
  </p>

  <img data-img="https://hellocoding.de/assets/placeholder/pic-6.jpg" alt="Random Picture" />

  <p>
    Lorem ipsum dolor sit amet, <strong>consetetur sadipscing elitr</strong>, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo
    dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
    <strong>Lorem ipsum</strong> dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, <i>sed diam voluptua</i>. At vero eos et accusam et justo
    duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
  </p>

  <img data-img="https://hellocoding.de/assets/placeholder/pic-7.jpg" alt="Random Picture" />

  <p>
    Lorem ipsum dolor sit amet, <strong>consetetur sadipscing elitr</strong>, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo
    dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
    <strong>Lorem ipsum</strong> dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, <i>sed diam voluptua</i>. At vero eos et accusam et justo
    duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
  </p>

  <img data-img="https://hellocoding.de/assets/placeholder/pic-8.jpg" alt="Random Picture" />

  <p>
    Lorem ipsum dolor sit amet, <strong>consetetur sadipscing elitr</strong>, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo
    dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
    <strong>Lorem ipsum</strong> dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, <i>sed diam voluptua</i>. At vero eos et accusam et justo
    duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
  </p>

</div>
const images = document.querySelectorAll('.example-code img');

observer = new IntersectionObserver(generateEntries,{threshold: 0.8,root: document.querySelector('div.example-code'),rootMargin:'32px'});

images.forEach(e => {
  observer.observe(e);
})

function generateEntries(entries){
    entries.forEach(setImages)
}

function setImages(e){
    if(e.intersectionRatio * 100 > 75 && !e.target.classList.contains('loaded')){
        e.target.src = e.target.dataset.img;
        e.target.classList.add('loaded');
    }
}

Elemente in die Seite Faden lassen

Um ein Element in die Seite faden zu lassen, benötigt es nur eine CSS Klasse, wenn das Element nicht im Bild ist. Und zusätzlich eine CSS Klasse, die hinzugefügt wird, wenn das Element im Bild ist. Mit einer Transition wird das ganze dann rund.

.example-code {
  margin: 2rem auto;
  max-width: 45rem;
  max-height: 80vh;
  font-size: 1.2rem;
  font-family: 'Barlow', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  line-height: 1.5;
  overflow-x: scroll;
}

.example-code img {
  display: block;
  width: 80%;
  border-radius: 0.5rem;
  margin: 2rem auto;
  transition: all 2s;
  transform: translateX(-150px);
  opacity: 0;
}

.example-code img.animate{
  opacity: 1;
  transform: translateX(0);
}
<div class="example-code">

  <h1>Intersection Observer - Animation</h1>

  <p>
    Lorem ipsum dolor sit amet, <strong>consetetur sadipscing elitr</strong>, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo
    dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
    <strong>Lorem ipsum</strong> dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, <i>sed diam voluptua</i>. At vero eos et accusam et justo
    duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
  </p>

  <img src="https://hellocoding.de/assets/placeholder/pic-3.jpg" alt="Random Picture" />

  <p>
    Lorem ipsum dolor sit amet, <strong>consetetur sadipscing elitr</strong>, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo
    dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
    <strong>Lorem ipsum</strong> dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, <i>sed diam voluptua</i>. At vero eos et accusam et justo
    duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
  </p>

  <img src="https://hellocoding.de/assets/placeholder/pic-4.jpg" alt="Random Picture" />

  <p>
    Lorem ipsum dolor sit amet, <strong>consetetur sadipscing elitr</strong>, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo
    dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
    <strong>Lorem ipsum</strong> dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, <i>sed diam voluptua</i>. At vero eos et accusam et justo
    duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
  </p>

  <img src="https://hellocoding.de/assets/placeholder/pic-5.jpg" alt="Random Picture" />

  <p>
    Lorem ipsum dolor sit amet, <strong>consetetur sadipscing elitr</strong>, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo
    dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
    <strong>Lorem ipsum</strong> dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, <i>sed diam voluptua</i>. At vero eos et accusam et justo
    duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
  </p>

  <img src="https://hellocoding.de/assets/placeholder/pic-6.jpg" alt="Random Picture" />

  <p>
    Lorem ipsum dolor sit amet, <strong>consetetur sadipscing elitr</strong>, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo
    dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
    <strong>Lorem ipsum</strong> dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, <i>sed diam voluptua</i>. At vero eos et accusam et justo
    duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
  </p>

  <img src="https://hellocoding.de/assets/placeholder/pic-7.jpg" alt="Random Picture" />

  <p>
    Lorem ipsum dolor sit amet, <strong>consetetur sadipscing elitr</strong>, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo
    dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
    <strong>Lorem ipsum</strong> dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, <i>sed diam voluptua</i>. At vero eos et accusam et justo
    duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
  </p>

  <img src="https://hellocoding.de/assets/placeholder/pic-8.jpg" alt="Random Picture" />

  <p>
    Lorem ipsum dolor sit amet, <strong>consetetur sadipscing elitr</strong>, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo
    dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
    <strong>Lorem ipsum</strong> dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
    invidunt ut labore et dolore magna aliquyam erat, <i>sed diam voluptua</i>. At vero eos et accusam et justo
    duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
  </p>

</div>
const images = document.querySelectorAll('.example-code img');

observer = new IntersectionObserver(generateEntries,{threshold: [...range(0,102),1],root: document.querySelector('div.example-code'),rootMargin:'32px'});

images.forEach(e => {
  observer.observe(e);
})

function generateEntries(entries){
    entries.forEach(setAnimation)
}

function setAnimation(e){
    if(e.intersectionRatio * 100 > 40 && e.isIntersecting){
        e.target.classList.add('animate');
    }else{
        e.target.classList.remove('animate');
    }
}

function range(r,a){return Array.apply(0,Array(a-1)).map((a,n)=>"0."+(n+r))} 

Zusammenfassung

Der Intersection Observer biete eine Reihe von neuen Ansätzen, um alt bekannte Problem auf eine ganz neue Art zu lösen - aus diesem Grund bin ich ein großer Fan vom Intersection Observer. Hast du weitere Ideen, was man damit lösen könnte, hierlasse dazu gerne ein Kommentar.

Bildquelle - Vielen Dank an die Ersteller:innen für dieses Bild
Kommentare zum Artikel

Es sind noch keine Kommentare vorhanden? Sei der/die Erste und verfasse einen Kommentar zum Artikel "Ist das Element im Viewport? JavaScript Intersection Observer"!

Kommentar schreiben

Vom Autor Empfohlen
close