1. はじめに
ウェブの従来の位置計算メカニズムは、DOMの状態を明示的にクエリすることに依存しており、これは(高コストな)スタイル再計算やレイアウトを引き起こすことで知られています。そして、多くの場合、この情報を継続的にポーリングすることによる大きなパフォーマンスのオーバーヘッドの原因となっています。
しかし、これらの挙動に依存した一般的な慣習が発展してきました。例として、以下のようなものがあります:
-
DOMやデータのカスタム事前・遅延読み込みの構築。
-
データにバインドされた高性能なスクロールリストの実装。これらのリストはデータセットの一部のみをロード・レンダリングします。モバイルインタラクションの中心的なイディオムです。
-
要素の可視性の計算。特に、 広告ネットワークではインプレッションの収益化のために広告の「可視性」報告が要求されるようになりました。これにより、多くのサイトがスクロールハンドラを乱用するようになり (スクロール時にジャンクが発生)、同期レイアウトによるリードバック(rAFループで不要なクリティカルワークを発生)、 さらには「真の」要素の可視性を計算するためにプラグインベースの特殊なソリューションを使うようになりました(プラグインアーキテクチャのオーバーヘッドも伴います)。
これらのユースケースにはいくつかの共通点があります:
-
これらは、個々の要素の状態を他の要素(またはグローバルなビューポート)に対する受動的な「クエリ」として表現できます。
-
厳密なレイテンシ要件を課しません。つまり、情報は非同期(例えば別スレッドから)で提供されても問題ありません。
-
これらは既存のウェブプラットフォーム機能のほぼすべての組み合わせで十分にサポートされていないため、広く使われているにも関わらず開発者に多大な労力を要求します。
注目すべき非目的は、実際に表示された内容についてのピクセル単位の正確な情報です(これは、フィルタ・webgl・その他の機能の影響下で、特定のブラウザアーキテクチャでは効率的に取得するのが非常に困難な場合があります)。 これらすべてのシナリオにおいて、情報は少し遅れて、完璧な合成結果データがなくても有用です。
Intersection Observer APIは、上記の問題に対処し、開発者がある要素の位置を他の要素やグローバルなビューポートに対して非同期にクエリできる新しい方法を提供します。 非同期での情報提供は、高コストなDOMやスタイルのクエリ、継続的なポーリング、カスタムプラグインの使用を不要にします。 これらの手法を排除することで、アプリケーションのCPU・GPU・エネルギー消費を大幅に削減できます。
var observer= new IntersectionObserver( changes=> { for ( const changeof changes) { console. log( change. time); // 変更が発生した時刻のタイムスタンプ console. log( change. rootBounds); // ルートの切り取られていない領域 console. log( change. boundingClientRect); // target.getBoundingClientRect() console. log( change. intersectionRect); // boundingClientRect(包含ブロックの先祖でクリップされ、rootBoundsと交差) console. log( change. intersectionRatio); // intersectionRectの面積とboundingClientRectの面積の比率 console. log( change. target); // Elementターゲット } }, {}); // 特定のターゲットElementのインターセクションイベントを監視する。 observer. observe( target); // 特定のターゲットElementのインターセクションイベントの監視を停止する。 observer. unobserve( target); // すべてのターゲット要素のしきい値イベントの監視を停止する。 observer. disconnect();
2. インターセクションオブザーバー
Intersection Observer APIは、開発者が ターゲットDOM 要素の可視性と位置をインターセクションルートに対して把握できるようにします。
2.1. IntersectionObserverCallback
callback =IntersectionObserverCallback undefined (sequence <IntersectionObserverEntry >,entries IntersectionObserver );observer
このコールバックは、ターゲットの インターセクションルートとの交差状態に変更があった場合、処理モデルに従って呼び出されます。
2.2. IntersectionObserverインターフェース
IntersectionObserver
インターフェースは、インターセクションルートと1つ以上の ターゲット Element
の交差状態の変化を監視するために使用できます。
インターセクションルートは、IntersectionObserver
の root
属性が null でなければその値です。
null の場合は、トップレベル閲覧コンテキストの document
ノードとなり、
これは 暗黙的ルートと呼ばれます。
IntersectionObserver
で root
が null でないものは 明示的ルートオブザーバー と呼ばれます。
この場合、ターゲット Element
は 包含ブロックチェーン内で root
の子孫である必要があります。
IntersectionObserver
で root
が null のものは 暗黙的ルートオブザーバー と呼ばれます。
暗黙的ルートオブザーバーの有効な ターゲットは、
トップレベル閲覧コンテキスト内のすべての Element、
および 子孫閲覧コンテキストのリストに含まれる
ネストされた閲覧コンテキスト内のすべての Element
です。
暗黙的ルートオブザーバーを扱う際、APIは次の区別を行います。 ターゲットの 関連設定オブジェクト の オリジン が 同一オリジンドメインであり、 トップレベルオリジンと一致している場合は 同一オリジンドメインターゲット となります。 それ以外は クロスオリジンドメインターゲット となります。 明示的ルートオブザーバーの ターゲット も 同一オリジンドメインターゲット となります。 これは ターゲットが document と インターセクションルートが同じである必要があるためです。
注: MutationObserverでは、
MutationObserverInit
のオプションは
observe()
に渡されますが、IntersectionObserver
では
コンストラクタに渡されます。MutationObserverの場合、各Node
ごとに異なるフィルタ属性セットを持つことができますが、
IntersectionObserverでは、同じオプションセットで複数のターゲットを追跡するために単一のオブザーバーを使うことも、各ターゲットごとに異なるオブザーバーを使うこともできます。
rootMargin
やthreshold
を各ターゲットごとに設定するのは、追加ユースケースを解決せず複雑さが増すだけです。必要に応じて、将来的にobserve()ごとのオプション提供も検討されます。
[Exposed =Window ]interface {IntersectionObserver (constructor IntersectionObserverCallback ,callback optional IntersectionObserverInit = {});options readonly attribute (Element or Document )?root ;readonly attribute DOMString rootMargin ;readonly attribute DOMString scrollMargin ;readonly attribute FrozenArray <double >thresholds ;undefined observe (Element );target undefined unobserve (Element );target undefined disconnect ();sequence <IntersectionObserverEntry >takeRecords (); };
new IntersectionObserver(callback, options)-
新しいIntersectionObserverの初期化 アルゴリズムをcallbackとoptionsを指定して実行した結果を返します。
observe(target)-
ターゲットElementの監視アルゴリズムをthisとtarget で実行します。
unobserve(target)-
ターゲットElementの監視解除アルゴリズムをthisとtarget で実行します。
注:
MutationObserverにはunobserve()は実装されていません。IntersectionObserverでは、unobserve()は遅延読み込みユースケースへの対応です。targetが表示された後は、追跡する必要がありません。 全targetでdisconnect()を呼び出して残りをobserve()するか、各targetごとに別のIntersectionObserverを作るのは手間です。 disconnect()-
thisの内部
[[ObservationTargets]]スロット内の各targetについて:-
targetの内部
[[RegisteredIntersectionObservers]]スロットから、IntersectionObserverRegistrationレコードでobserverプロパティがthisに一致するものを削除します。 -
thisの内部
[[ObservationTargets]]スロットからtargetを削除します。
-
takeRecords()-
-
thisの内部
[[QueuedEntries]]スロットのコピーをqueueとします。 -
thisの内部
[[QueuedEntries]]スロットをクリアします。 -
queueを返します。
-
root, 型は(Element or Document)、readonly、nullable-
rootはIntersectionObserverのコンストラクタに渡された値、渡されていなければnullです。 rootMargin, 型はDOMString、readonly-
ルート交差矩形に適用されるオフセットで、 交差判定に使うボックスを拡張・縮小します。これらのオフセットは同一オリジンドメインターゲットの 処理時のみ適用され、クロスオリジンドメインターゲット には無視されます。
取得時は、
[[rootMargin]]の各要素をスペース区切りで直列化した結果を返します。ピクセル長は数値+"px"、パーセンテージは数値+"%"となります。 これは、options.rootMarginに渡された値と必ずしも一致しません。何も渡されなかった場合は"0px 0px 0px 0px"になります。 scrollMargin, 型はDOMString、readonly-
インターセクションルートからターゲットまでのパス上の scrollportに適用されるオフセットで、交差判定に使うclip矩形を拡張・縮小します。
取得時は、
[[scrollMargin]]の各要素をスペース区切りで直列化した結果を返します。ピクセル長は数値+"px"、パーセンテージは数値+"%"となります。 これはoptions.scrollMarginに渡された値と必ずしも一致しません。何も渡されなかった場合は"0px 0px 0px 0px"になります。 thresholds, 型はFrozenArray<double>、readonly-
しきい値のリストで、数値昇順に並んでいます。各しきい値は監視対象の交差面積/バウンディングボックス面積の比率です。 しきい値をまたぐ度に通知が発生します。 options.
thresholdが指定されなかった場合や空の場合は[0]となります。
Element
のcomputed styleでoverflowプロパティにより内容が要素のpadding
edgeでクリップされる場合は、コンテントクリップを持つと定義されます。
ルート交差矩形は、IntersectionObserver
でターゲットと比較する矩形です。
- もし
IntersectionObserverが暗黙ルートオブザーバーなら - ルートはトップレベル閲覧コンテキストの
documentであるものとして扱い、以下のdocumentに関するルールを適用します。 - もしインターセクションルートが
documentなら documentの ビューポートのサイズ(この処理段階に到達するのは、documentが完全にアクティブな場合のみ)。- それ以外でインターセクションルートがコンテントクリップを持つ場合
- 要素のpadding area。
- それ以外の場合
- 要素のバウンディングボックス取得の結果。
ルート交差矩形の計算時、
同一オリジンドメインターゲットの場合は、
IntersectionObserverの
[[rootMargin]]
スロットのオフセットで拡張します。CSSのmarginプロパティのように、
4つの値はそれぞれ上・右・下・左の拡張量で、正の値は外側への拡張です。
パーセンテージは拡張前の矩形の幅に対して解決されます。
注: rootMargin
はインターセクションルート自体にのみ適用されます。
ターゲットElement
がインターセクションルート以外の祖先によってクリップされている場合、そのクリップにはrootMargin
の影響はありません。
- スクロールポートにスクロールマージンを適用する
-
scrollportの交差矩形を 同一オリジンドメインターゲットに対して計算する場合、 矩形は
IntersectionObserverの[[scrollMargin]]スロットのオフセットに従って CSSのmarginプロパティと同様の方法で拡張されます。 4つの値は、それぞれ上、右、下、左の端がどれだけオフセットされるかを示し、正の長さは外側へのオフセットを意味します。 パーセンテージは拡張前の矩形の幅に対して解決されます。これらのオフセットは同一オリジンドメインターゲットを扱う場合のみ適用されます。 クロスオリジンドメインターゲットの場合は無視されます。
Note:
scrollMarginは、ターゲットがすべてのスクロール可能な先祖によって インターセクションルートまでクリッピングされる際に影響します。scrollMarginとrootMarginの両方がスクロール可能なインターセクションルートの矩形に適用されます。
Note: ルート交差矩形およびscrollport交差矩形はピンチズームの影響を受けず、調整されていないビューポートを報告します。 これはピンチズームの意図(虫眼鏡のように動作し、レイアウトを変更しない)と一致します。
マージンをパースする(ルートまたはスクロール) 入力文字列marginStringから 4つのピクセル長またはパーセンテージのリスト、もしくは失敗を返す:
-
コンポーネント値のリストをパースする marginString の結果をtokensとして保存する。
-
tokensからすべての空白トークンを取り除く。
-
tokensの長さが4より大きい場合、失敗を返す。
-
tokensに要素が0個の場合、tokensを["0px"]に設定する。
-
tokens内の各tokenを置き換える:
-
tokenが<percentage>トークンなら、同等のパーセンテージに置き換える。
-
それ以外の場合は失敗を返す。
-
tokensが1要素の場合、その要素を3つ複製してtokensへ追加する。 2要素の場合は各要素を複製して追加する。 3要素の場合は2番目の要素を複製して追加する。
-
tokensを返す。
2.3. IntersectionObserverEntryインターフェース
[Exposed =Window ]interface {IntersectionObserverEntry (constructor IntersectionObserverEntryInit );intersectionObserverEntryInit readonly attribute DOMHighResTimeStamp time ;readonly attribute DOMRectReadOnly ?rootBounds ;readonly attribute DOMRectReadOnly boundingClientRect ;readonly attribute DOMRectReadOnly intersectionRect ;readonly attribute boolean isIntersecting ;readonly attribute double intersectionRatio ;readonly attribute Element target ; };dictionary {IntersectionObserverEntryInit required DOMHighResTimeStamp ;time required DOMRectInit ?;rootBounds required DOMRectInit ;boundingClientRect required DOMRectInit ;intersectionRect required boolean ;isIntersecting required double ;intersectionRatio required Element ; };target
boundingClientRect, 型 DOMRectReadOnly、読み取り専用-
DOMRectReadOnlyは、targetの バウンディングボックスを取得して得られます。 intersectionRect, 型 DOMRectReadOnly、読み取り専用-
boundingClientRectを、targetの各祖先の クリップ矩形(ただしrootを除く)で交差させ、 さらに root の交差矩形 と交差させます。 この値は、targetが root の交差矩形内で実際に見える部分を表します。 isIntersecting, 型 boolean、読み取り専用-
targetがrootと交差していれば true、そうでなければ false です。 このフラグにより、IntersectionObserverEntryが 交差状態から非交差状態への遷移を示す場合と、IntersectionObserverEntryが 非交差状態から交差状態への遷移(交差矩形の面積がゼロの場合、例えば端同士が接する交差やboundingClientRectの面積がゼロの場合)を区別できます。 intersectionRatio, 型 double、読み取り専用-
boundingClientRectの面積がゼロでない場合、intersectionRectの面積をboundingClientRectの面積で割った比率になります。 それ以外の場合、isIntersectingが true なら 1、そうでなければ 0 となります。 rootBounds, 型 DOMRectReadOnly、読み取り専用、nullable-
同一オリジンドメインターゲットの場合、 root の交差矩形 になります。 それ以外の場合は
nullです。 ターゲットが 閲覧コンテキストが intersection root と異なる場合、 この値はboundingClientRectやintersectionRectと 異なる座標系になります。 target, 型 Element、読み取り専用-
Elementは、 intersection root との交差状態が変更された要素です。 time, 型 DOMHighResTimeStamp、読み取り専用-
この属性は、通知を生成した IntersectionObserver インスタンスに関連付けられたグローバルオブジェクトの タイムオリジン を基準とした、 交差が記録された時刻に対応する
DOMHighResTimeStampを返します。
2.4. IntersectionObserverInit辞書
dictionary { (IntersectionObserverInit Element or Document )?root =null ;DOMString rootMargin = "0px";DOMString scrollMargin = "0px"; (double or sequence <double >)threshold = 0; };
root, 型(Element or Document)、nullable、デフォルトはnullrootMargin, 型 DOMString、デフォルトは"0px"-
CSS の margin プロパティに類似しており、 1~4個のコンポーネントからなる文字列です。 各コンポーネントは 絶対長またはパーセンテージです。
"5px" // すべてのマージンが 5px "5px 10px" // 上下 = 5px、左右 = 10px "-10px 5px 8px" // 上 = -10px、左右 = 5px、下 = 8px "-10px -5px 5px 8px" // 上 = -10px、右 = -5px、下 = 5px、左 = 8px scrollMargin, 型 DOMString、デフォルトは"0px"-
rootMarginと同様で、 1~4個のコンポーネントからなる文字列です。 各コンポーネントは 絶対長またはパーセンテージです。例については上記
rootMarginを参照してください。 threshold, 型(double or sequence<double>)、デフォルトは0-
コールバックをトリガーするしきい値(複数可)のリストです。 intersectionRect の面積が任意のしきい値以上から未満に変化した場合、またはその逆の場合、コールバックが呼び出されます。
しきい値は [0, 1.0] の範囲で、バウンディングボックスを取得した target の矩形面積に対する割合を表します。
Note: 0.0 は実質的に「1ピクセル以上が非ゼロ」の意味になります。
3. 処理モデル
このセクションでは、Intersection Observer APIを実装する際にユーザーエージェントが実行すべき手順を概説します。
3.1. 内部スロット定義
3.1.1. ドキュメント
各document
は、IntersectionObserverTaskQueuedフラグを持ち、初期値はfalseです。
3.1.2. 要素
Element
オブジェクトは、内部[[RegisteredIntersectionObservers]]
スロットを持ち、初期値は空のリストです。
このリストはIntersectionObserverRegistrationレコードを保持します。
これらは、observerプロパティ(IntersectionObserverを保持)、
previousThresholdIndexプロパティ
(observerのthresholdsプロパティの長さの範囲内で-1からの数値)、
previousIsIntersectingプロパティ
(boolean値)を持ちます。
3.1.3. IntersectionObserver
IntersectionObserver
オブジェクトは、内部[[QueuedEntries]]および[[ObservationTargets]]スロット(ともに初期値は空リスト)、
[[callback]]スロット
(IntersectionObserver(callback, options)で初期化)を持ちます。
また、内部[[rootMargin]]および[[scrollMargin]]スロット(4つのピクセル長またはパーセンテージのリスト)も持ちます。
3.2. アルゴリズム
3.2.1. 新しいIntersectionObserverの初期化
新しいIntersectionObserverを初期化するには、IntersectionObserverCallback
callbackとIntersectionObserverInit
辞書optionsを指定して、次の手順を実行します:
-
thisを新しい
IntersectionObserverオブジェクトとする -
thisの内部
[[callback]]スロットにcallbackをセットする。 -
options.
rootMarginから マージンをパースすることを試みる。 リストが返された場合、 thisの内部[[rootMargin]]スロットにそれをセットする。 そうでなければ、throwでSyntaxError例外を投げる。 -
options.
scrollMarginから マージンをパースすることを試みる。 リストが返された場合、 thisの内部[[scrollMargin]]スロットにそれをセットする。 そうでなければ、throwでSyntaxError例外を投げる。 -
thresholdsをoptions.
thresholdと同じリストにする。 -
thresholds内に0.0未満または1.0超の値があれば、 throwで
RangeError例外を投げる。 -
thresholdsを昇順にソートする。
-
thresholdsが空なら
0を追加する。 -
thresholds属性のgetterはこの昇順のthresholdsリストを返す。 -
thisを返す。
3.2.2. ターゲットElementの監視
ターゲットElementの監視は、IntersectionObserver
observerとElement
targetを指定して、次の手順を実行します:
-
targetがobserverの内部
[[ObservationTargets]]スロットに含まれていれば、returnする。 -
intersectionObserverRegistrationを
IntersectionObserverRegistrationレコードとして、observerプロパティにobserver、previousThresholdIndexプロパティに-1、previousIsIntersectingプロパティにfalseをセットする。 -
intersectionObserverRegistrationをtargetの内部
[[RegisteredIntersectionObservers]]スロットに追加する。 -
targetをobserverの内部
[[ObservationTargets]]スロットに追加する。
3.2.3. ターゲットElementの監視解除
ターゲットElementの監視解除は、IntersectionObserver
observerとElement
targetを指定して、次の手順を実行します:
-
targetの内部
[[RegisteredIntersectionObservers]]スロットから、IntersectionObserverRegistrationレコード(observerプロパティがthisと等しいもの)を削除する(存在する場合)。 -
thisの内部
[[ObservationTargets]]スロットからtargetを削除する(存在する場合)。
3.2.4. Intersection Observerタスクのキューイング
IntersectionObserverタスクソースは タスクソースであり、 § 3.2.5 Intersection Observerへの通知のタスクをスケジューリングするために使われます。
intersection observerタスクをキューイングするには、
document
documentを指定して、次の手順を実行します:
-
documentのIntersectionObserverTaskQueuedフラグがtrueなら、returnする。
-
documentのIntersectionObserverTaskQueuedフラグをtrueにセットする。
-
documentの イベントループに関連付けられた IntersectionObserverタスクソース上で タスクをキューイングし、 Intersection Observerへの通知を実行する。
3.2.5. Intersection Observerへの通知
Intersection
Observerへの通知は、
document
documentについて、次の手順を実行します:
-
documentのIntersectionObserverTaskQueuedフラグをfalseにセットする。
-
notify listを、documentのDOMツリー内に
rootを持つすべてのIntersectionObserverのリストとする。 -
notify list内の各
IntersectionObserverオブジェクトobserverについて、以下を実行:-
observerの内部
[[QueuedEntries]]スロットが空なら、次へ。 -
queueをobserverの内部
[[QueuedEntries]]スロットのコピーとする。 -
observerの内部
[[QueuedEntries]]スロットをクリアする。 -
callbackをobserverの内部
[[callback]]スロットの値とする。 -
callbackを、第1引数にqueue、第2引数にobserver、 callback this valueとしてobserverを指定して呼び出す。 例外が投げられた場合、例外を報告する。
-
3.2.6. IntersectionObserverEntryのキューイング
IntersectionObserverEntryをキューイングするには、
IntersectionObserver
observer、document
document、DOMHighResTimeStamp
time、DOMRect各種
rootBounds、boundingClientRect、intersectionRect、isIntersectingフラグ、
Element
targetを指定して、次の手順を実行します:
-
IntersectionObserverEntryを、time、rootBounds、boundingClientRect、 intersectionRect、isIntersecting、targetを引数として生成する。 -
それをobserverの内部
[[QueuedEntries]]スロットに追加する。 -
intersection observerタスクをキューイングする(document)。
3.2.7. ターゲットElementとルートの交差領域の計算
交差領域を計算するには、 target targetと intersection root rootを指定して、次の手順を実行します:
-
intersectionRectをtargetのバウンディングボックスを取得した結果とする。
-
containerをtargetの包含ブロックとする。
-
containerがrootでない間:
-
containerがネストされた閲覧コンテキストの
documentなら、 intersectionRectをそのdocumentの ビューポートでクリップし、 containerをその閲覧コンテキストコンテナに更新する。 -
intersectionRectをcontainerの座標空間にマップする。
-
containerがスクロールコンテナなら、
IntersectionObserverの[[scrollMargin]]を containerのクリップ矩形にスクロールポートにスクロールマージンを適用するに従って適用する。 -
containerがcontent clipやcssのclip-pathプロパティを持つ場合、 containerのクリップをintersectionRectに適用する。
-
containerが閲覧コンテキストのルート要素なら、 containerをその閲覧コンテキストの
documentに更新する。 それ以外の場合は、containerの包含ブロックに更新する。
-
-
intersectionRectをrootの座標空間にマップする。
-
intersectionRectをrootの交差矩形と交差させて更新する。
-
intersectionRectを返す。
3.2.8. インターセクション監視の更新手順の実行
インターセクション監視の更新手順を実行するには、Document documentとタイムスタンプtimeを指定して、以下の手順を実行します:
-
observer listを、documentのDOMツリー内に
IntersectionObserverのrootが存在するすべてのリストとする。 トップレベル閲覧コンテキストの場合、暗黙的ルートオブザーバーも含まれます。 -
observer list内の各observerについて:
-
rootBoundsをobserverのルート交差矩形とする。
-
observerの内部
[[ObservationTargets]]スロット内の各targetについて、observe()が呼ばれた順で処理する:-
以下を初期化:
-
thresholdIndex = 0
-
isIntersecting = false
-
targetRect =
DOMRectReadOnly(x, y, width, heightを0に設定) -
intersectionRect =
DOMRectReadOnly(x, y, width, heightを0に設定)
-
-
intersection rootが暗黙的ルートでない場合、 かつtargetが
documentと同じでない場合は、ステップ11へスキップ。 -
intersection rootが
Elementの場合、 targetがintersection rootの 包含ブロックチェーンの子孫でなければ、ステップ11へスキップ。 -
targetRectに
DOMRectReadOnlyとして バウンディングボックスを取得した値をセットする。 -
intersectionRectをtargetとobserverのintersection rootで交差領域を計算するアルゴリズムの結果とする。
-
targetArea = targetRectの面積。
-
intersectionArea = intersectionRectの面積。
-
isIntersecting = targetRectとrootBoundsが交差または端同士が接していればtrue(交差面積がゼロでも、rootBoundsやtargetRectがゼロ面積でもtrue)。
-
targetAreaがゼロでなければ、intersectionRatio = intersectionArea / targetArea。
それ以外の場合、isIntersectingがtrueなら1、falseなら0。 -
thresholdIndexを、observer.
thresholdsの 各値がintersectionRatioを超える最初のインデックス、 もしくはintersectionRatioが最後の要素以上ならlengthとする。 -
intersectionObserverRegistrationをtargetの内部
[[RegisteredIntersectionObservers]]スロット内でobserverプロパティがobserverと等しいレコードとする。 -
previousThresholdIndexを intersectionObserverRegistrationの
previousThresholdIndexプロパティとする。 -
previousIsIntersectingを intersectionObserverRegistrationの
previousIsIntersectingプロパティとする。 -
thresholdIndexがpreviousThresholdIndexと一致しない、またはisIntersectingがpreviousIsIntersectingと一致しない場合は、IntersectionObserverEntryのキューイングを行い、 observer、time、rootBounds、targetRect、intersectionRect、isIntersecting、targetを渡す。
-
thresholdIndexをintersectionObserverRegistrationの
previousThresholdIndexプロパティに代入する。 -
isIntersectingをintersectionObserverRegistrationの
previousIsIntersectingプロパティに代入する。
-
-
3.3. IntersectionObserverのライフタイム
IntersectionObserver
は、次の両方の条件を満たすまで存続します:
- オブザーバーへのスクリプト参照がないこと
- オブザーバーがいずれのターゲットも監視していないこと
IntersectionObserver
は、observerのunobserve()メソッドがターゲットを引数に呼ばれるか、observerのdisconnect()が呼ばれるまで、ターゲットの監視を継続します。
3.4. 外部仕様との統合
3.4.1. HTML処理モデル: イベントループ
Intersection Observerの処理ステップは、「レンダリングの更新」ステップ内のサブステップとして、 HTMLイベントループ処理モデルに存在します。
3.4.2. 初期IntersectionObserverターゲットの保留
document
は、以下の条件を満たすIntersectionObserverが1つ以上存在する場合、初期IntersectionObserverターゲットの保留があるとされます:
- observerの
rootがdocument内に存在する(トップレベル閲覧コンテキストの場合、暗黙的ルートオブザーバーも含む)。 - observerの
[[ObservationTargets]]スロットに、まだIntersectionObserverEntryがキューイングされていないtargetが1つ以上存在する。
HTMLイベントループ処理モデルの「レンダリングの更新」ステップで、 「不要なレンダリング」ステップには以下の要件を追加してレンダリング更新のスキップ条件とします:
- documentが初期IntersectionObserverターゲットの保留を持たない。
4. アクセシビリティに関する考慮事項
このセクションは規範的ではありません。
IntersectionObserver仕様(本書)のコア部分に関して、既知のアクセシビリティの考慮事項はありません。 ただし、本仕様を活用・参照する関連仕様や提案には、それぞれアクセシビリティに関する考慮事項が存在する可能性があります。特に、HTML § 2.5.7 レイジーローディング属性やCSS Containment 2 § 4 要素の内容を完全に抑制する: content-visibilityプロパティの仕様は、HTML § 6.9 ページ内検索、 HTML § 6.6.3 tabindex属性、および 空間ナビゲーション に影響を及ぼす可能性があります。
5. プライバシーとセキュリティ
このセクションは規範的ではありません。
このAPIに関連する主なプライバシーの懸念は、クロスオリジンiframe(すなわち クロスオリジンドメインターゲットの場合)で実行されるコードに提供される情報に関するものです。特に:
-
iframeがグローバルビューポート内に存在するかどうかを公開することのプライバシーへの影響については、普遍的な合意はありません。
-
このAPIがグローバルビューポート自体のジオメトリ情報を探る目的で利用され、ユーザーのハードウェア構成を推測されるリスクがあります。
rootMarginやscrollMarginの効果を無効化し、クロスオリジンドメインターゲットに対してrootBoundsを抑制する理由は、このような探査を防ぐためです。
なお、IntersectionObserver以前は、
ウェブ開発者は他のAPIを非常に巧妙(かつ時に不適切)な方法で利用して、
IntersectionObserverで得られる情報を引き出していました。
実際のところ、このAPIは他の手段ですでに取得可能だった情報以外を公開していません。
さらに、IntersectionObserverは
DOMHighResTimeStampを使用しますが、これ自体もプライバシー・セキュリティ上の考慮事項があります。ただし、
IntersectionObserverがタイミング関連の攻撃に脆弱である可能性は低いです。
タイムスタンプはレンダリング更新ごとに最大1回しか生成されず(§ 3.4.1 HTML処理モデル: イベントループ参照)、
一般的なタイミング攻撃には頻度が不十分です。
6. 国際化
このセクションは規範的ではありません。
国際化に関する既知の問題はありません。
7. 謝辞
技術的な意見や提案を寄せて仕様の改善に貢献してくださったすべてのコントリビューターに感謝します。