Mit Intersection Observer v2 können Sie nicht nur Überschneidungen beobachten, sondern auch erkennen, ob das sich überschneidende Element zum Zeitpunkt der Überschneidung sichtbar war.
Intersection Observer v1 ist eine dieser APIs, die wahrscheinlich überall beliebt sind. Da sie jetzt auch von Safari unterstützt wird, ist sie endlich in allen wichtigen Browsern universell einsetzbar. Wenn Sie Ihr Wissen über die API auffrischen möchten, empfehle ich Ihnen, sich den unten eingebetteten Supercharged Microtip von Surma zu Intersection Observer v1 anzusehen.
Hier finden Sie einen ausführlichen Artikel von Surma.
Intersection Observer v1 wurde für eine Vielzahl von Anwendungsfällen verwendet, z. B. für das Lazy Loading von Bildern und Videos, Benachrichtigungen, wenn Elemente position: sticky
erreichen, und das Auslösen von Analyseereignissen.
Die vollständigen Details finden Sie in der Intersection Observer-Dokumentation auf MDN. Hier ist eine kurze Erinnerung daran, wie die Intersection Observer v1 API im einfachsten Fall aussieht:
const onIntersection = (entries) => {
for (const entry of entries) {
if (entry.isIntersecting) {
console.log(entry);
}
}
};
const observer = new IntersectionObserver(onIntersection);
observer.observe(document.querySelector('#some-target'));
Was ist das Problem mit Intersection Observer v1?
Intersection Observer v1 ist zwar gut, aber nicht perfekt. Es gibt einige seltene Fälle, in denen die API nicht ausreicht. Sehen wir uns das genauer an.
Mit der Intersection Observer v1 API lässt sich ermitteln, wann ein Element in den Viewport des Fensters gescrollt wird. Sie gibt jedoch nicht an, ob das Element durch andere Seiteninhalte verdeckt wird (d. h., ob das Element verdeckt ist) oder ob die visuelle Darstellung des Elements durch visuelle Effekte wie transform
, opacity
, filter
usw. geändert wurde, wodurch es effektiv unsichtbar werden kann.
Bei einem Element im Dokument der obersten Ebene können diese Informationen durch Analysieren des DOM über JavaScript ermittelt werden, z. B. über DocumentOrShadowRoot.elementFromPoint()
, und dann durch weitere Analysen.
Wenn sich das betreffende Element in einem Drittanbieter-Iframe befindet, können dieselben Informationen nicht abgerufen werden.
Warum ist die tatsächliche Sichtbarkeit so wichtig?
Das Internet ist leider ein Ort, der böswillige Akteure mit schlechten Absichten anzieht.
Ein unseriöser Publisher, der Pay-per-Click-Anzeigen auf einer Inhaltswebsite schaltet, könnte beispielsweise versuchen, Nutzer dazu zu bringen, auf seine Anzeigen zu klicken, um die Werbeeinnahmen des Publishers zu steigern – zumindest für kurze Zeit, bis das Werbenetzwerk ihn erwischt.
Normalerweise werden solche Anzeigen in iFrames ausgeliefert.
Wenn der Publisher Nutzer dazu bringen möchte, auf solche Anzeigen zu klicken, kann er die Anzeigen-iFrames mithilfe einer CSS-Regel iframe { opacity: 0; }
vollständig transparent machen und sie über etwas Attraktives legen, z. B. ein süßes Katzenvideo, auf das Nutzer tatsächlich klicken möchten.
Das nennt man Clickjacking.
Ein Beispiel für einen solchen Clickjacking-Angriff finden Sie im oberen Bereich dieser Demo. Versuchen Sie, sich das Katzenvideo anzusehen und den „Trickmodus“ zu aktivieren.
Sie werden feststellen, dass die Anzeige im iFrame „denkt“, dass sie zulässige Klicks erhalten hat, auch wenn sie völlig transparent war, als Sie (scheinbar unabsichtlich) darauf geklickt haben.
Wie wird dieses Problem in Intersection Observer v2 behoben?
Mit Intersection Observer v2 wird das Konzept der Erfassung der tatsächlichen „Sichtbarkeit“ eines Zielelements eingeführt, wie sie von einem Menschen definiert wird.
Wenn Sie eine Option im IntersectionObserver
-Konstruktor festlegen, enthalten sich überschneidende IntersectionObserverEntry
-Instanzen ein neues boolesches Feld mit dem Namen isVisible
.
Ein true
-Wert für isVisible
ist eine starke Garantie der zugrunde liegenden Implementierung, dass das Zielelement nicht durch andere Inhalte verdeckt wird und keine visuellen Effekte angewendet werden, die die Darstellung auf dem Bildschirm verändern oder verzerren.
Ein false
-Wert bedeutet hingegen, dass die Implementierung diese Garantie nicht geben kann.
Ein wichtiges Detail der Spezifikation ist, dass die Implementierung falsch negative Ergebnisse (d. h. das Festlegen von isVisible
auf false
, auch wenn das Zielelement vollständig sichtbar und unverändert ist) melden darf.
Aus Leistungsgründen oder anderen Gründen arbeiten Browser nur mit Bounding Boxes und geradliniger Geometrie. Sie versuchen nicht, pixelgenaue Ergebnisse für Änderungen wie border-radius
zu erzielen.
Falsch positive Ergebnisse sind jedoch unter keinen Umständen zulässig. Das bedeutet, dass isVisible
nicht auf true
gesetzt werden darf, wenn das Zielelement nicht vollständig sichtbar und unverändert ist.
Wie sieht der neue Code in der Praxis aus?
Der Konstruktor IntersectionObserver
verwendet jetzt zwei zusätzliche Konfigurationsattribute: delay
und trackVisibility
.
delay
ist eine Zahl, die die Mindestverzögerung in Millisekunden zwischen Benachrichtigungen des Beobachters für ein bestimmtes Ziel angibt.
trackVisibility
ist ein boolescher Wert, der angibt, ob der Observer Änderungen an der Sichtbarkeit eines Ziels verfolgt.
Wichtig: Wenn trackVisibility
gleich true
ist, muss delay
mindestens 100
betragen (d. h. maximal eine Benachrichtigung alle 100 ms).
Wie bereits erwähnt, ist die Berechnung der Sichtbarkeit aufwendig. Diese Anforderung dient als Vorsichtsmaßnahme gegen Leistungseinbußen und hohen Akkuverbrauch. Der verantwortliche Entwickler verwendet den größten zulässigen Wert für die Verzögerung.
Gemäß der aktuellen Spezifikation wird die Sichtbarkeit so berechnet:
Wenn das Attribut
trackVisibility
des Beobachtersfalse
ist, gilt das Ziel als sichtbar. Dies entspricht dem aktuellen v1-Verhalten.Wenn das Ziel eine effektive Transformationsmatrix hat, die nicht einer 2D-Übersetzung oder einer proportionalen 2D-Hochskalierung entspricht, gilt das Ziel als unsichtbar.
Wenn das Ziel oder ein Element in der zugehörigen Blockkette eine effektive Deckkraft ungleich 1,0 hat, gilt das Ziel als unsichtbar.
Wenn auf das Ziel oder ein Element in der zugehörigen Blockkette Filter angewendet werden, gilt das Ziel als unsichtbar.
Wenn bei der Implementierung nicht garantiert werden kann, dass das Ziel nicht durch andere Seiteninhalte verdeckt wird, gilt es als unsichtbar.
Das bedeutet, dass aktuelle Implementierungen ziemlich konservativ sind, was die Sichtbarkeit angeht.
Wenn Sie beispielsweise einen kaum wahrnehmbaren Graustufenfilter wie filter: grayscale(0.01%)
anwenden oder eine fast unsichtbare Transparenz mit opacity: 0.99
festlegen, wird das Element unsichtbar.
Unten finden Sie ein kurzes Codebeispiel, das die neuen API-Funktionen veranschaulicht. Die Logik für das Klick-Tracking können Sie im zweiten Abschnitt der Demo in Aktion sehen. Versuchen Sie es jetzt mit dem Welpenvideo. Aktivieren Sie den „Trick Mode“ wieder, um sich sofort in einen unseriösen Publisher zu verwandeln und zu sehen, wie mit Intersection Observer v2 verhindert wird, dass unzulässige Anzeigenklicks erfasst werden. Dieses Mal hilft uns Intersection Observer v2. 🎉
<!DOCTYPE html>
<!-- This is the ad running in the iframe -->
<button id="callToActionButton">Buy now!</button>
// This is code running in the iframe.
// The iframe must be visible for at least 800ms prior to an input event
// for the input event to be considered valid.
const minimumVisibleDuration = 800;
// Keep track of when the button transitioned to a visible state.
let visibleSince = 0;
const button = document.querySelector('#callToActionButton');
button.addEventListener('click', (event) => {
if ((visibleSince > 0) &&
(performance.now() - visibleSince >= minimumVisibleDuration)) {
trackAdClick();
} else {
rejectAdClick();
}
});
const observer = new IntersectionObserver((changes) => {
for (const change of changes) {
// ⚠️ Feature detection
if (typeof change.isVisible === 'undefined') {
// The browser doesn't support Intersection Observer v2, falling back to v1 behavior.
change.isVisible = true;
}
if (change.isIntersecting && change.isVisible) {
visibleSince = change.time;
} else {
visibleSince = 0;
}
}
}, {
threshold: [1.0],
// 🆕 Track the actual visibility of the element
trackVisibility: true,
// 🆕 Set a minimum delay between notifications
delay: 100
}));
// Require that the entire iframe be visible.
observer.observe(document.querySelector('#ad'));
Weitere Informationen
- Aktueller Editor-Entwurf der Intersection Observer-Spezifikation
- Intersection Observer v2 im Status der Chrome-Plattform
- Intersection Observer v2 Chromium-Fehler.
- Blink Intent to Implement-Beitrag
Danksagungen
Vielen Dank an Simeon Vincent, Yoav Weiss und Mathias Bynens für das Überprüfen dieses Artikels sowie an Stefan Zager für das Überprüfen und Implementieren der Funktion in Chrome. Hero-Image von Sergey Semin auf Unsplash.