信頼は良い、モニタリングはよりよい: Intersection Observer v2

Intersection Observer v2 では、交差点自体を監視できるだけでなく、 は、交差時に交差要素が表示されていたかどうかを検出します。

Intersection Observer v1 は、広く愛用されている API の 1 つですが、 Safari でサポートされていますが、 ついにすべての主要なブラウザで普遍的に使えるようになりました。API を簡単に復習すると、 Surma の 交差点でのスーパーチャージ マイクロチップ 以下に埋め込まれている Observer v1。 また、 記事をご覧ください。 Intersection Observer v1 は、次のような幅広いユースケースで使用されています。 画像や動画の遅延読み込み 要素が position: sticky に達したときに通知されるようにする アナリティクス イベントの呼び出し、 その他多数

詳しくは、 MDN の Intersection Observer のドキュメント 簡単にご説明いたしますと、Intersection Observer v1 API は、 基本的な場合:

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

Intersection Observer v1 の課題は何ですか?

Intersection Observer v1 は優れたツールですが、完璧ではありません。他にも 特殊なケースとして API が不足しています。詳しく見ていきましょう。 Intersection Observer v1 API は、要素がスクロールし、 要素が隠れているかどうかはわからない。 他のページ コンテンツによる影響(つまり要素が隠蔽されている場合)や、 要素の視覚表示が transformopacityfilter など。実質的に非表示にすることができます。

最上位のドキュメントの要素の場合、この情報は、 たとえば DocumentOrShadowRoot.elementFromPoint() 掘り下げていきます 一方、同じ情報を取得できるのは、対象の要素が 配置する必要があります

実際の可視性がこれほど重要なのはなぜですか?

残念ながら、インターネットは悪意を持った不正な行為者を引き寄せる場所です。 たとえば、コンテンツ サイトでクリック課金型広告を配信する悪質なパブリッシャーが、 パブリッシャー様の広告支払いを増やす目的で、 (広告ネットワークで捕捉するまでの短い期間)待てと表示されるなど)。 通常、このような広告は iframe で配信されます。 そのような広告をユーザーにクリックさせたい場合、広告の iframe を作成できます。 CSS ルール iframe { opacity: 0; } を適用して iframe をオーバーレイすることで、完全に透明にする かわいい猫の動画など ユーザーがクリックしたくなるような動画を含めます これをクリックジャッキングと呼びます。 このセクションの上部のセクションでは、このようなクリックジャッキング攻撃の実際の動作を確認できます。 デモ(猫の動画を「視聴」してみてください) 「トリック モード」を有効にします)。 iframe 内の広告が過去に発生したものであっても、 (意図せず)クリックされても、完全に透明な状態になっています。

透明なスタイル設定を行い、見栄えの良いものの上に重ねて、ユーザーをだましてクリックさせる。

Intersection Observer v2 では、この問題はどのように修正されますか?

Intersection Observer v2 では、実際の「可視性」をトラッキングするというコンセプトが導入されています。ターゲットの 要素を定義します。 モジュールで IntersectionObserver コンストラクタ 交差 IntersectionObserverEntry すると、isVisible という名前の新しいブール値フィールドがインスタンスに追加されます。 isVisibletrue 値は、基盤となる実装による強力な保証です。 ターゲット要素が他のコンテンツによって完全に遮られていないこと 画面上の表示を変更または歪めるような視覚効果が適用されていないこと。 一方、false 値は実装がその保証を行えないことを意味します。

アラートの重要な詳細情報は、 仕様 実装で偽陰性の報告(つまり、isVisible の設定)が許可されている点です。 ターゲット要素が完全に表示されていて、変更されていない場合でも、false に変更します。 パフォーマンスなどの理由から、ブラウザは境界を使った処理に制限を設ける 直線幾何学フル解像度で画像を取得しようとせず border-radius のような変更。

ただし、偽陽性はいかなる状況( ターゲット要素が完全に表示されず、変更されていない場合には、isVisibletrue に変更します。

新しいコードの実際の例

IntersectionObserver コンストラクタが、次の 2 つの追加構成プロパティを受け取るようになりました。delay および trackVisibilitydelay は、次の期間からの通知間の最小遅延をミリ秒単位で示す数値です。 オブザーバーになります。 trackVisibility は、オブザーバーがターゲットの変更を追跡するかどうかを示すブール値です。 可視化。

ここで、trackVisibilitytrue の場合、delay は 少なくとも 100(つまり、100 ミリ秒ごとに 1 件の通知未満)にします。 前述のように、可視性の計算にはコストがかかります。この要件は、 パフォーマンスの低下やバッテリー消費量の抑制に 役立ちます責任者は、 遅延の最大許容値

現在の spec、公開設定: 次のように計算されます。

  • オブザーバーの trackVisibility 属性が false の場合、ターゲットは可視と見なされます。 これは現在の v1 の動作に対応しています。

  • ターゲットに 2 次元変換以外の有効な変換行列がある場合 比例した 2D アップスケーリングでは、ターゲットは非表示と見なされます。

  • ターゲットまたはそれを含むブロック チェーンの要素の実効不透明度が 1.0 の場合、ターゲットは非表示とみなされます。

  • ターゲットまたはそれを含むブロック チェーンの要素にフィルタが適用されている場合、 ターゲットは非表示とみなされます

  • ターゲットが他のページによって完全に隠されることを保証できない場合 ターゲットは非表示とみなされます。

つまり、現在の実装では可視性を保証するという点でかなり控えめな実装になっています。 たとえば、filter: grayscale(0.01%) のような、ほとんど目立たないグレースケール フィルタを適用します。 または、opacity: 0.99 でほとんど見えない透明度を設定すると、すべて要素がレンダリングされます。 表示されません。

以下に、新しい API の機能を示す短いコードサンプルを示します。そのキャンペーンのクリック トラッキングと デモの 2 番目のセクションで示したロジックの実例 (ここでは、子犬の動画を「視聴」してみます)。必ず「トリックモード」を有効にしてくださいすぐに 「あいまいなパブリッシャー」に変身して、Intersection Observer v2 を回避する様子をご覧ください 不正な広告クリックのトラッキングを防ぎます。 今度は Intersection Observer v2 に支援を求めました!🎉

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

謝辞

今後とも Simeon Vincent をよろしくお願いいたします。 Yoav WeissMathias Bynens および Stefan Zager をご覧ください をご覧ください。 ヒーロー画像作成: Sergey Semin(Unsplash より)