Intersection Observerが簡単で便利!要素がビューポートに表示されているかを判定できる
Post on:2017年8月10日
スクロールした際にヘルプや広告を表示したり、無限スクロールでコンテンツを読み込ませたり、画像の遅延ロードなど、要素がビューポートに表示されているかをトリガーにするのには、なかなか面倒なJavaScriptが必要でした。
例えば、スクロールやサイズ変更のイベントを取得し、getBoundingClientRect()などのDOM APIでビューポートからの相対位置を手動で計算します。
この今までの方法は面倒で非効率的でしたが、主要なブラウザに実装されているIntersectionObserver APIを使用すると、非常に簡単に取得することができます。
Intersection Observer comes to Firefox
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、著者様にライセンスを得て翻訳しています。
- 「IntersectionObserver()」の基本的な動作
- 可視の判定をしていると思いましたか?
- ハンドラの基本
- 更に使いこなすためのオプション
- ほかのオプション
- ブラウザのサポート
- 参考リソース
「IntersectionObserver()」の基本的な動作
さっそく、IntersectionObserver APIの最も基本的な動作を見てみましょう。
まずは、簡単なJavaScriptです。
1 2 |
let observer = new IntersectionObserver(handler); observer.observe(Target); // <-- この要素を監視 |
下記のデモで、その動作が確認できます。
スクロールして、ターゲットがビューポートに表示されている間はTrueを返します。
1つのObserver(監視者)で多くのターゲット要素を同時に監視することができます。その際は、各ターゲットに対してobserver.observe()を繰り返すだけです。
上記の対象はビューポートですが、div要素など特定のコンテナにすることもできます。
可視の判定をしていると思いましたか?
IntersectionObserversはデフォルトで、ターゲット要素がブラウザのビューポートと呼ばれるページの表示領域と重なる(または交差する「Intersection」)量を計算します。
ターゲットがビューポートに交差したかを監視
しかし、Observerは実際の画面上の可視性に関係なく、要素が任意の親要素とどれだけ交差するかを監視することができます。これはdiv要素のコンテナ内で無限スクロールするリストのように、コンテンツをロードするウィジェットに有用です。このような場合、ウィジェットはIntersectionObserversを使用して、コンテナを満たすのに十分なコンテンツをロードすることができます。
分かりやすくするために、ここでは「可視」という用語を使用しますが、IntersectionObserversは文字通りの可視性に限定されないことを覚えておいてください。
ハンドラの基本
ハンドラは、2つの引数を受け取るコールバックです。
- IntersectionObserverEntryオブジェクトのリスト、各オブジェクトにはハンドラの最後の呼び出し以降にターゲットの交差がどのように変化されたか、それぞれメタデータが含まれています。
- Observer自体への参照。
Observerはデフォルトでブラウザのビューポートを監視しています。つまり、上記のデモでは、isIntersectingプロパティを調べて、ターゲット要素の一部が表示可能かどうかを判断する必要があります。
デフォルトでは、ハンドラはターゲット要素が完全にオフスクリーンから部分的に可視になるか、またはその逆に移行する瞬間にのみ実行されますが、部分的に可視の要素と完全に可視の要素を区別したい場合はどうなるでしょうか?
しきい値「threshold」の出番です!
更に使いこなすためのオプション
ハンドラのコールバックに加えて、IntersectionObserverコンストラクタはいくつかのオプションが用意されています。このオプションの1つに、ハンドラを呼び出すためのブレークポイントを定義するしきい値「threshold」があります。
1 2 3 |
let observer = new IntersectionObserver(handler, { threshold: 0 // <-- これがデフォルトです }); |
デフォルトの値は0で、ターゲットが部分的に表示されるか完全に非表示されるたびにハンドラを呼び出します。thresholdに1を設定すると、ターゲットが完全に可視と部分可視の間で反転するたびにハンドラが呼び出され、ターゲットがいずれかの方向に50%の可視性のポイントを通過すると0.5に設定されます。
下記のデモのように「threshold: [0, 1]」と配列にすることもできます。
ターゲットをゆっくりとスクロールしてビューポートに出し入れして、その動作を見てみてください。
ターゲットが完全に表示されはじめ、その時intersectionRatioは1です、そこから更にスクロールすると2回変化します。正確な値は環境により異なりますが、1回目は0.87、その後は0です。ターゲットがビューポートにスクロールバックされると、intersectionRatioは0.05に変わり、その後は1に変わります。0と1は理にかなっていますが、追加の値はどこから来ているのでしょうか? また、0と1の間の他の数字はどうなっていると思いますか?
しきい値はトランジションに関して定義されます。ハンドラは、ターゲットのintersectionRatioがしきい値の1つを超えて拡大・縮小したときをブラウザが認識するたびに通知します。しきい値を[0, 1]にすると、ターゲットが非可視のライン(0)と可視のライン(1)を横切るたびにブラウザに通知され、3つの状態が効果的に定義されます。3つの状態とは、完全に可視、部分的に可視、可視ではない。です。
intersectionRatioの観測値は、ブラウザがアイドルである瞬間を待ってから交差点を確認し報告する必要があるため、テストごとに異なります。これらの計算はスクロールやユーザーの入力よりも低い優先度で、バックグラウンドで行われます。
デモは編集が可能なので、しきい値を追加または削除してみてください。そして、ハンドラがいつどこで実行されるかを確認してみてください。
ほかのオプション
IntersectionObserverコンストラクタには、ほかにも2つのオプションがあります。
- root: 観察するエリア(デフォルト: ブラウザのビューポート)
- rootMargin: 交差を計算するときにルートの論理サイズを縮小・拡大する量(デフォルト: 0px 0px 0px 0px)
rootを変更すると、Observerはブラウザのビューポートだけでなく、親コンテナ要素との交差をチェックすることができます。
rootMarginを増やすと、ターゲットが特定の領域に近づいたときを検出することができます。例えば、表示される直前に表示されていない画像をロードすることができます。
ブラウザのサポート
IntersectionObserverをサポートするブラウザは、下記の通りです。
- Edge 15+
- Chrome 51+
- Firefox 55+
- Opera 38+
IE 7+, Safari 6+など、非サポートブラウザに対応するにはIntersectionObserver polyfillが利用できます。
参考リソース
- MDN: Intersection Observer
- Cross-browser Polyfill
- Can I Use(ブラウザのサポート情報)
sponsors