Vertrauen ist gut, Beobachtung ist besser: Intersection Observer v2

Mit Intersection Observer v2 können nicht nur Kreuzungen an sich, sondern auch ermitteln, ob das sich überschneidende Element zum Zeitpunkt der Kreuzung sichtbar war.

Intersection Observer v1 ist eine dieser APIs, die wahrscheinlich überall beliebt ist. Safari wird auch unterstützt, Endlich ist er in allen gängigen Browsern einsetzbar. Zur Erinnerung: Ich empfehle mir, sich Surma Aufgeladener Microtip an Kreuzung Beobachter v1, die unten eingebettet ist. Sie können auch Surmas ausführlicher Artikel. Intersection Observer v1 wurden für eine Vielzahl von Anwendungsfällen verwendet, Lazy Loading von Bildern und Videos, benachrichtigt werden, wenn Elemente position: sticky erreichen, Auslösung von Analyseereignissen und vieles mehr.

Alle Einzelheiten finden Sie in der Intersection Observer Docs auf MDN Zur Erinnerung: So sieht die Intersection Observer v1 API in den meisten Einfacher Fall:

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'));

Welche Herausforderungen gibt es bei Intersection Observer v1?

Intersection Observer v1 ist großartig, aber nicht perfekt. Es gibt einige Grenzfälle an, bei denen das API nicht ausreicht. Sehen wir uns das genauer an. Die Intersection Observer v1 API informiert Sie, wenn ein Element in den Darstellungsbereich des Fensters. Hier wird aber nicht angegeben, ob das Element verdeckt ist. durch anderen Seiteninhalt (d. h. verdecktes Element) oder durch Die visuelle Anzeige des Elements wurde durch visuelle Effekte wie transform, opacity, filter usw., wodurch sie effektiv unsichtbar werden kann.

Für ein Element im Dokument auf oberster Ebene lassen sich diese Informationen durch Analysieren das DOM über JavaScript, z. B. über DocumentOrShadowRoot.elementFromPoint() und dann weitere Informationen zu erhalten. Im Gegensatz dazu können dieselben Informationen nicht abgerufen werden, wenn das betreffende Element die sich in einem Drittanbieter-iFrame befindet.

Warum ist die tatsächliche Sichtbarkeit so wichtig?

Leider ist das Internet ein Ort, an dem böswillige Akteure mit schlimmeren Absichten anziehen. So könnte z. B. ein zwielichtiger Publisher, der Pay-per-Click-Anzeigen auf einer Content-Website schaltet, Anreize schaffen. Nutzer dazu zu bringen, auf ihre Anzeigen zu klicken, um die Anzeigeneinnahmen des Publishers zu steigern (mindestens für kurze Zeit, bis sie vom Werbenetzwerk erfasst werden. Solche Anzeigen werden normalerweise in iFrames ausgeliefert. Wenn der Publisher Nutzer dazu bringen wollte, auf solche Anzeigen zu klicken, könnte er die Anzeigen-iFrames Die CSS-Regel iframe { opacity: 0; } wird angewendet und die iFrames werden verdeckt wie ein süßes Katzenvideo, auf das die Nutzer klicken möchten. Dies wird als Clickjacking bezeichnet. Ein solcher Clickjacking-Angriff in Aktion sehen Sie im oberen Abschnitt dieses demo (versuch, das Katzenvideo anzusehen) und aktiviere den Trickmodus). Sie werden feststellen, dass die Anzeige im iFrame „denkt“, dass es legitime Klicks erhalten hat, völlig transparent, wenn du (unabsichtlich) darauf geklickt hast.

Nutzer werden dazu verleitet, auf eine Anzeige zu klicken, indem sie transparent gestaltet wird und über etwas attraktives überlagern.

Wie kann Intersection Observer v2 dieses Problem beheben?

Intersection Observer v2 führt das Konzept der Erfassung der tatsächlichen eines Ziels wie ein Mensch es definieren würde. Indem Sie im Menü IntersectionObserver-Konstruktor, sich überschneidende IntersectionObserverEntry Instanzen enthalten dann ein neues boolesches Feld mit dem Namen isVisible. Ein true-Wert für isVisible ist eine starke Garantie von der zugrunde liegenden Implementierung Das Zielelement ist vollständig von anderen Inhalten verdeckt. und es werden keine visuellen Effekte angewendet, die die Darstellung auf dem Bildschirm verändern oder verzerren. Im Gegensatz dazu bedeutet ein false-Wert, dass die Implementierung diese Garantie nicht garantieren kann.

Ein wichtiges Detail der Spezifikation ist, dass bei der Implementierung falsch negative Ergebnisse gemeldet werden dürfen (d. h. das Festlegen von isVisible) auf false, auch wenn das Zielelement vollständig sichtbar und unverändert ist. Aus Leistungs- oder anderen Gründen beschränken sich Browser darauf, mit Begrenzungen zu arbeiten. Rechtecke und geradlinige Geometrie; versuchen sie nicht, perfekte Pixel-Ergebnisse für Änderungen wie border-radius.

Falsch positive Ergebnisse sind jedoch unter keinen Umständen zulässig. isVisible bis true, wenn das Zielelement nicht vollständig sichtbar und unverändert ist.

Wie sieht der neue Code in der Praxis aus?

Der IntersectionObserver-Konstruktor verwendet jetzt zwei zusätzliche Konfigurationsattribute: delay und trackVisibility. Die delay ist eine Zahl, die die minimale Verzögerung zwischen Benachrichtigungen in Millisekunden angibt von für ein bestimmtes Ziel. Der trackVisibility ist ein boolescher Wert, der angibt, ob der Beobachter Änderungen an der Sichtbarkeit.

Wichtig: Wenn trackVisibility den Wert true hat, muss delay unter mindestens 100 (d. h. nicht mehr als eine Benachrichtigung alle 100 ms). Wie bereits erwähnt, ist die Berechnung der Sichtbarkeit teuer und diese Anforderung ist eine Vorsichtsmaßnahme Verschlechterung der Leistung und des Akkuverbrauchs. Der verantwortliche Entwickler nutzt die größter tolerierbarer Wert für die Verzögerung.

Laut der aktuellen spec, ist die Sichtbarkeit wie folgt berechnet:

  • Wenn das trackVisibility-Attribut des Beobachters false ist, gilt das Ziel als sichtbar. Das entspricht dem aktuellen Verhalten von V1.

  • Wenn das Ziel eine andere effektive Transformationsmatrix als eine 2D-Verschiebung hat oder proportionalen 2D-Skalierungsvorgang ist, gilt das Ziel als unsichtbar.

  • Wenn das Ziel oder ein Element in seiner Blockkette eine andere effektive Deckkraft als 1,0 ist, gilt das Ziel als unsichtbar.

  • Wenn auf das Ziel oder ein Element in der Blockkette, die es enthält, Filter angewendet werden, gilt das Ziel als unsichtbar.

  • Wenn bei der Implementierung nicht garantiert werden kann, dass das Ziel vollständig von einer anderen Seite verdeckt wird wird das Ziel als unsichtbar angesehen.

Das bedeutet, dass aktuelle Implementierungen ziemlich konservativ sind und Sichtbarkeit garantieren. Beispielsweise wird durch Anwendung eines kaum erkennbaren Graustufenfilters wie filter: grayscale(0.01%) oder durch Festlegen einer fast unsichtbaren Transparenz mit opacity: 0.99 wird das Element unsichtbar sind.

Im Folgenden finden Sie ein kurzes Codebeispiel, das die neuen API-Funktionen veranschaulicht. Sie können das Klick-Tracking finden Sie im zweiten Abschnitt der Demo. (Aber versuche jetzt, das Welpenvideo anzusehen). Achte darauf, den Trickmodus zu aktivieren wieder zur sofortigen werden Sie in einen zwielichtigen Publisher und sehen Sie, wie Intersection Observer v2 verhindert, nicht legitime Anzeigenklicks erfasst werden. Dieses Mal unterstützt Intersection Observer v2! 🎉

Intersection Observer v2 verhindert einen unbeabsichtigten Klick auf eine Anzeige.

<!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'));

Danksagungen

Dank Simeon Vincent Yoav Weiss und Mathias Bynens für die Rezension dieses Artikels sowie von Stefan Zager zur Überprüfung und Implementierung der Funktion in Chrome. Hero-Image von Sergey Semin auf Unsplash