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.
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.
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);
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))}
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))}
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');
}
}
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))}
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.
Hinterlasse mir gerne einen Kommentar zum Artikel und wie er dir weitergeholfen hat beziehungsweise, was dir helfen würde das Thema besser zu verstehen. Oder hast du einen Fehler entdeckt, den ich korrigieren sollte? Schreibe mir auch dazu gerne ein Feedback!
Es sind noch keine Kommentare vorhanden? Sei der/die Erste und verfasse einen Kommentar zum Artikel "Ist das Element im Viewport? JavaScript Intersection Observer"!