IntersectionObserver を使用すると、監視対象の要素がブラウザのビューポートに入ったり、ビューポートから出たりしたタイミングを把握できます。
DOM 内の要素が可視ビューポートに入ったタイミングをトラッキングしたいとします。画像をジャストインタイムで読み込むため、またはユーザーが特定の広告バナーを実際に見ているかどうかを把握する必要がある場合に、この方法が適しています。スクロール イベントをフックするか、定期的なタイマーを使用してその要素で getBoundingClientRect()
を呼び出すことで、この処理を行うことができます。
ただし、この方法では、getBoundingClientRect()
の呼び出しごとにブラウザがページ全体を再レイアウトするため、ウェブサイトに大きなジャンクが発生し、非常に遅くなります。サイトが iframe 内に読み込まれていることがわかっていて、ユーザーが要素をいつ見ることができるかを知りたい場合、状況はさらに困難になります。単一オリジン モデルとブラウザでは、iframe を含むウェブページのデータにアクセスできません。これは、iframe を使用して頻繁に読み込まれる広告でよく発生する問題です。
IntersectionObserver
は、この可視性テストをより効率的に行うことを目的に設計されており、すべての最新ブラウザに実装されています。IntersectionObserver
を使用すると、検出された要素がブラウザのビューポートに出入りしたタイミングを把握できます。
IntersectionObserver
を作成する方法
この API は比較的小規模で、例を使用して説明するのが最適です。
const io = new IntersectionObserver(entries => {
console.log(entries);
}, {
/* Using default options. Details below */
});
// Start observing an element
io.observe(element);
// Stop observing an element
// io.unobserve(element);
// Disable entire IntersectionObserver
// io.disconnect();
IntersectionObserver
のデフォルト オプションを使用すると、要素が部分的にビューに表示されたときと、ビューポートから完全に外れたときの両方でコールバックが呼び出されます。
複数の要素を監視する必要がある場合は、observe()
を複数回呼び出して、同じ IntersectionObserver
インスタンスを使用して複数の要素を監視できます。これは推奨される方法です。
entries
パラメータがコールバックに渡されます。これは IntersectionObserverEntry
オブジェクトの配列です。各オブジェクトには、観測された要素のいずれかの更新された交差点データが含まれています。
🔽[IntersectionObserverEntry]
time: 3893.92
🔽rootBounds: ClientRect
bottom: 920
height: 1024
left: 0
right: 1024
top: 0
width: 920
🔽boundingClientRect: ClientRect
// ...
🔽intersectionRect: ClientRect
// ...
intersectionRatio: 0.54
🔽target: div#observee
// ...
rootBounds
は、ルート要素(デフォルトではビューポート)で getBoundingClientRect()
を呼び出した結果です。boundingClientRect
は、監視対象の要素で呼び出された getBoundingClientRect()
の結果です。intersectionRect
は、これらの 2 つの長方形の交差点であり、検出された要素のどの部分が表示されているかを効果的に示します。intersectionRatio
はこれに関連しており、要素の表示範囲を示します。この情報を利用することで、アセットが画面に表示されるまで待たずに、アセットをジャストインタイムで読み込むなどの機能を実装できるようになります。効率的である。
IntersectionObserver
はデータを非同期的に提供し、コールバック コードはメインスレッドで実行されます。また、仕様では、IntersectionObserver
の実装で requestIdleCallback()
を使用する必要があると明記されています。つまり、指定したコールバックの呼び出しは優先度が低く、ブラウザによってアイドル状態のときに呼び出されます。これは意図的な設計上の決定です。
スクロールする div
要素内のスクロールはあまり好きではありませんが、判断するのは私ではなく、IntersectionObserver
でもありません。options
オブジェクトは root
オプションを取ります。このオプションを使用すると、ビューポートの代わりにルートを定義できます。root
は、検出されたすべての要素の祖先である必要があります。
すべてのものを交差させましょう。
いいえ。デベロッパーが悪い!これは、ユーザーの CPU サイクルを慎重に使用しているわけではありません。無限スクロールを例に考えてみましょう。このシナリオでは、DOM にセンチネルを追加して、それらを監視(およびリサイクル)することを強くおすすめします。無限スクロールの最後のアイテムの近くにセンチネルを追加する必要があります。そのセレンティールが視界に入ると、コールバックを使用してデータを読み込み、次のアイテムを作成し、DOM に接続して、セレンティールの位置を適宜調整できます。センチネルを適切にリサイクルする場合、observe()
を追加で呼び出す必要はありません。IntersectionObserver
は引き続き動作します。
最新情報を教えてください
前述のように、コールバックは、監視対象の要素が部分的にビューに表示されたときに 1 回、ビューポートから消えたときに 1 回トリガーされます。これにより、IntersectionObserver
は「要素 X はビュー内にあるか?」という質問に対する回答を返します。ただし、ユースケースによっては、それだけでは不十分な場合があります。
そこで threshold
オプションの出番です。これにより、intersectionRatio
しきい値の配列を定義できます。コールバックは、intersectionRatio
がこれらの値のいずれかを越えるたびに呼び出されます。threshold
のデフォルト値は [0]
です。これはデフォルトの動作を示しています。threshold
を [0, 0.25, 0.5, 0.75, 1]
に変更すると、要素の 1/4 が追加で表示されるたびに通知が届きます。
他の方法はありますか?
現時点では、上記のオプション以外に 1 つのオプションのみがあります。rootMargin
を使用すると、ルートの余白を指定できるため、交差点に使用される領域を効果的に拡大または縮小できます。これらの余白は、"10px 20px 30px 40px"
のような CSS スタイルの文字列を使用して指定します。上、右、下、左の余白をそれぞれ指定します。要約すると、IntersectionObserver
オプション構造体には次のオプションがあります。
new IntersectionObserver(entries => {/* … */}, {
// The root to use for intersection.
// If not provided, use the top-level document's viewport.
root: null,
// Same as margin, can be 1, 2, 3 or 4 components, possibly negative lengths.
// If an explicit root element is specified, components may be percentages of the
// root element size. If no explicit root element is specified, using a
// percentage is an error.
rootMargin: "0px",
// Threshold(s) at which to trigger callback, specified as a ratio, or list of
// ratios, of (visible area / total area) of the observed element (hence all
// entries must be in the range [0, 1]). Callback will be invoked when the
// visible ratio of the observed element crosses a threshold in the list.
threshold: [0],
});
<iframe>
マジック
IntersectionObserver
は、広告サービスやソーシャル ネットワーク ウィジェットを念頭に置いて設計されています。これらのウィジェットでは <iframe>
要素が頻繁に使用され、視界内にあるかどうかを把握することが有用です。<iframe>
がその要素のいずれかを監視している場合、<iframe>
のスクロールと、<iframe>
を含むウィンドウのスクロールによって、適切なタイミングでコールバックがトリガーされます。ただし、後者の場合、オリジン間でデータが漏洩しないように、rootBounds
は null
に設定されます。
IntersectionObserver
Not とは
IntersectionObserver
は、意図的にピクセル パーフェクトでも低レイテンシでもないことに注意してください。スクロールに依存するアニメーションなどの実装に使用すると、厳密に言えば、使用するまでにデータが古くなるため、失敗する可能性があります。IntersectionObserver
の元のユースケースの詳細については、説明をご覧ください。
コールバックでどの程度の作業ができますか?
簡潔に: コールバックで時間を長く取るとアプリが遅くなります。一般的な方法がすべて適用されます。
要素を交差させる
IntersectionObserver
はすべての最新ブラウザで利用可能であるため、ブラウザでのサポートは良好です。必要に応じて、古いブラウザでポリフィルを使用できます。ポリフィルは WICG のリポジトリで入手できます。当然、ポリフィルを使用すると、ネイティブ実装で得られるパフォーマンス上のメリットは得られません。
IntersectionObserver
はすぐにご利用いただけます。考えたアイデアをお知らせください。