【この訳に固有の表記規約】
この訳の,~algoや定義の記述に利用されている各種記号( ~LET, ~IF, 此れ, ~THROW 等々)の意味や定義の詳細は,~SYMBOL_DEF_REFを~~参照されたし。
- 用語 `文書@ は、~HTML `Document$I ~interfaceを実装する~objの略記である。 同様に, `要素@ は、 `Element$I ~interfaceを実装する~objの略記である。
- %target.`xyz^sl という表記は、[ %target の `xyz^sl 内部~slot ]の略記である。
1. 序論
~webの伝統的な位置~計算の仕組みは、~DOM状態を明示的に照会することに依拠する。 それは、(高価な)~styleの再計算, および~layoutを生じさせることが既知である。 この情報の継続的な~pollingは、有意な処理能~overheadの要因になることは頻繁にある。 ◎ The web’s traditional position calculation mechanisms rely on explicit queries of DOM state that are known to cause (expensive) style recalculation and layout and, frequently, are a source of significant performance overhead due to continuous polling for this information.
次に挙げるもの含め、上述の挙動に依拠するような共通的な実施~自体は発展したが: ◎ A body of common practice has evolved that relies on these behaviors, however, including (but not limited to):
- ~DOMや~dataに対する~customな事前読込み/遅延読込みを築くとき。 ◎ Building custom pre- and deferred-loading of DOM and data.
- ~data集合の一部分を読込んで描画するような,~dataに束縛された高性能な~scroll用~listを実装するとき。 これは、携帯機器において中心的な対話上の成句になっている。 ◎ Implementing data-bound high-performance scrolling lists which load and render subsets of data sets. These lists are a central mobile interaction idiom.
-
要素の可視率を計算するとき。 特に,広告~networkでは、今や 収益集計~用に広告の “可視率” を報告することが要求されている。 その結果、多くの~siteが次のいずれかを用いている:
- ~scroll~handlerを濫用する(その結果、~scroll時に詰まる( “scroll jank” ))
- 同期的~layoutを呼出すような再読取り ( `requestAnimationFrame()^m ~loop内で不必要に重い仕事をさせる) 【例えば、 `getComputedStyle()^m で 最新の~layout情報を照会するなど。】
- 要素の “真の” 可視率を算出するため,~~外部~pluginによる解決策に頼る(~plugin~architectureによる~overheadすべてが伴われる)
これらの利用事例には、共通する性質がある: ◎ These use-cases have several common properties:
- 個々の要素の,他の要素(または大域的な表示域)に~~相対的な状態を、受動的に “照会するもの” として表現できる。 ◎ They can be represented as passive "queries" about the state of individual elements with respect to some other element (or the global viewport).
- 厳しい刻限を課すものではない。 つまり、情報は 代償なしに非同期的に送達できる(例えば別~threadから)。 ◎ They do not impose hard latency requirements; that is to say, the information can be delivered asynchronously (e.g. from another thread) without penalty.
- 既存の~web~platform特色機能の どの組合わせからも,ほぼ~supportに乏しいため、普及しているにもかかわらず,開発者は余計な労を要している。 ◎ They are poorly supported by nearly all combinations of existing web platform features, requiring extraordinary developer effort despite their widespread use.
目標とはされていないが注目すべき点として、実際に何が表示されているかについての,~pixel単位の情報もある(ある種の~browser~architectureにおいては、~filter, WebGL, その他の特色機能に面したとき,効率的にこれを得るのは極めて難しいこともある)。 この情報は、これらの局面すべてに有用になる — たとえ、遅延が少しあって,送達される~dataが不完全な組成結果によるときでも。 ◎ A notable non-goal is pixel-accurate information about what was actually displayed (which can be quite difficult to obtain efficiently in certain browser architectures in the face of filters, webgl, and other features). In all of these scenarios the information is useful even when delivered at a slight delay and without perfect compositing-result data.
交差~observer~APIは、[ 他の要素や大域的な表示域に~~相対的な 要素の位置を,非同期的に照会する ]ための新たな~methodを,開発者に与えることにより、上述の課題に取組む。 非同期的な送達により,[ ~costのかかる~DOMや~styleの照会- / 継続的な~polling / ~custom~pluginの利用 ]は不要になるので、~appは[ CPU, GPU, ~energy~cost ]を有意に抑制できるようになる。 ◎ The Intersection Observer API addresses the above issues by giving developers a new method to asynchronously query the position of an element with respect to other elements or the global viewport. The asynchronous delivery eliminates the need for costly DOM and style queries, continuous polling, and use of custom plugins. By removing the need for these methods it allows applications to significantly reduce their CPU, GPU and energy costs.
var %observer = new IntersectionObserver(%changes => { for (const %change of %changes) { /* 変化が生じた時点を表す時刻印: */ console.log(%change.`time$m); /* `交差~root$の区画: */ console.log(%change.`rootBounds$m); /* %target が占める区画( `getBoundingClientRect()$m ): */ console.log(%change.`boundingClientRect$m); /* `交差~root$内の %target の可視~域( `boundingClientRect^m を %target の`包含塊~連鎖$に属する各 先祖で~clipして得られる区画と `rootBounds^m との交差域): */ console.log(%change.`intersectionRect$m); /* %target が占める区画のうち, %target の可視~部分が占める比率( `intersectionRect^m の面積 ~DIV `boundingClientRect^m の面積 ): */ console.log(%change.`intersectionRatio$m); /* `~target$にされている要素( %target ): */ console.log(%change.`target$m); } }, {}); var %target = ... /* `~target$にする要素 */ ; /* 特定の`~target$に対し,交差~eventを~observeし始める: */ %observer.`observe(target)$m; /* 特定の`~target$に対し,~observeするのを停止する: */ %observer.`unobserve(target)$m; /* すべての`~target$に対し,~observeするのを停止する: */ %observer.`disconnect()$m;
var observer = new IntersectionObserver(changes => { for (const change of changes) { console.log(change.time); // Timestamp when the change occurred console.log(change.rootBounds); // Unclipped area of root console.log(change.boundingClientRect); // target.boundingClientRect() console.log(change.intersectionRect); // boundingClientRect, clipped by its containing block ancestors, and intersected with rootBounds console.log(change.intersectionRatio); // Ratio of intersectionRect area to boundingClientRect area console.log(change.target); // the Element target } }, {}); // Watch for intersection events on a specific target Element. observer.observe(target); // Stop watching for intersection events on a specific target Element. observer.unobserve(target); // Stop observing threshold events on all target elements. observer.disconnect();
2. 交差~observer
`交差~observer@ ~APIは、開発者が次を得れるようにする ⇒ `交差~root$の中での,[ `~target@ にされた~DOM要素 ]の[ 可視率, 位置 ] ◎ The Intersection Observer API enables developers to understand the visibility and position of target DOM elements relative to an intersection root.
2.1. `IntersectionObserverCallback^I
callback `IntersectionObserverCallback@I = void (sequence<`IntersectionObserverEntry$I> %entries, `IntersectionObserver$I %observer);
この~callbackは、`~target$と`交差~root$との交差に変化が生じたとき,`処理~model節$にしたがって呼出されることになる。 ◎ This callback will be invoked when there are changes to target’s intersection with the intersection root, as per the processing model.
【 見かけ上の交差が~UAからどう認識されるかは、~UAや処理能に依存するであろう — 例えば,高速に~scrollしたとき、その途上で表示が “間引かれた” 箇所があれば,その箇所にある~targetとの交差は見過ごされることになる — 交差が検出される時機は,~UAの各~描画~更新ごとなので。 】
2.2. `IntersectionObserver^I ~interface
`IntersectionObserver$I ~interfaceを利用すれば、[ `交差~root$と, `~target$にされた各`要素$ ]との交差における変化を~observeできる。 ◎ The IntersectionObserver interface can be used to observe changes in the intersection of an intersection root and one or more target Elements.
`IntersectionObserver$I ~objが有効な`~target$として~observeできるのは: ◎ ↓
- ~objの `root$m ~EQ ~NULL の場合、自動的に`暗黙的な~root$との交差を~observeする。 すなわち、`~top-level閲覧文脈$内にある どの`要素$も~observeできる — 内側の`入子の閲覧文脈$内も含め。
- 他の場合、`包含塊~連鎖$において `root$m の子孫である`要素$に限られる。
注記: `MutationObserver$I においては, `MutationObserverInit$I が各種~optionとして `~observe0()$m に渡される一方で、 `IntersectionObserver$I においては,各種~optionは構築子に渡される。 この違いは、 `MutationObserver$I においては,~observeする `Node$I ごとに 【変異の種類を】 絞込むための属性の集合を違えれることによる。 `IntersectionObserver$I においては、開発者は,同じ~option集合を用いる単独の~observerを利用して複数の~targetを追跡するか,または追跡する各~targetごとに異なる~observerを利用できる。 ◎ Note: In MutationObserver, the MutationObserverInit options are passed to observe() while in IntersectionObserver they are passed to the constructor. This is because for MutationObserver, each Node being observed could have a different set of attributes to filter for. For IntersectionObserver, developers may choose to use a single observer to track multiple targets using the same set of options; or they may use a different observer for each tracked target.
各 `~target$ごとに[ `rootMargin$mb / `threshold$mb ]値を違えれるようにしても、利用事例は拡がらず,より複雑になるだけに見える。 その必要が将来に生じたときは、後の~versionで `observe()$m ごとに~optionを供することもあり得る。 ◎ rootMargin or threshold values for each target seems to introduce more complexity without solving additional use-cases. Per-observe() options could be provided in the future if V2 introduces a need for it.
[Contructor(`IntersectionObserverCallback$I %callback, optional `IntersectionObserverInit$I %options), `Exposed$=Window] interface `IntersectionObserver@I { readonly attribute `Element$I? `root$m; readonly attribute DOMString `rootMargin$m; readonly attribute FrozenArray<double> `thresholds$m; void `observe$m(`Element$I %target); void `unobserve$m(`Element$I %target); void `disconnect$m(); sequence<`IntersectionObserverEntry$I> `takeRecords$m(); };
- `IntersectionObserver(callback, options)@m
-
この構築子の被呼出時には、次を走らす:
- %this ~LET 新たな `IntersectionObserver$I ~obj ◎ Let this be a new IntersectionObserver object
- %this.`callback$sl ~SET %callback ◎ Set this’s internal [[callback]] slot to callback.
- %this の `root$m ~SET %options の `root$mb 値 ◎ Set this.root to options.root.
- %~list ~LET `~root~marginを構文解析する$( %options の `rootMargin$mb 値 ) ◎ Attempt to parse a root margin from options.rootMargin.\
- ~IF[ %~list ~EQ `失敗^i ] ⇒ ~THROW `SyntaxError$E ◎ ↓
- %this.`rootMargin$sl ~SET %~list ◎ If a list is returned, set this’s internal [[rootMargin]] slot to that. Otherwise, throw a SyntaxError exception.
- %~threshold~list ~LET %options の `threshold$mb に等価な~list ◎ Let thresholds be a list equal to options.threshold.
- ~IF[ %~threshold~list 内の値に { 0.0 〜 1.0 } に入らないものがある ] ⇒ ~THROW `RangeError$E ◎ If any value in thresholds is less than 0.0 or greater than 1.0, throw a RangeError exception.
- %~threshold~list を昇順に~sortする ◎ Sort thresholds in ascending order.
- ~IF[ %~threshold~list は空である ] ⇒ %~threshold~list に 0 を付加する ◎ If thresholds is empty, append 0 to thresholds.
- %this の `thresholds$m ~SET %~threshold~list ◎ Set this.thresholds to thresholds.
- ~RET %this ◎ Return this.
- `observe(target)@m
-
被呼出時には、次を走らす: ◎ ↓
- ~IF[ %target ~IN 此れ.`ObservationTargets$sl ] ⇒ ~RET ◎ If target is in this’s internal [[ObservationTargets]] slot, return.
- %交差~observer登録 ~LET 次のようにされた 新たな`交差~observer登録$ ⇒# `~observer$rp ~SET 此れ, `前回の~threshold~index$rp ~SET −1, `前回に交差あり$rp ~SET ~F ◎ Let intersectionObserverRegistration be an IntersectionObserverRegistration record with an observer property set to this, a previousThresholdIndex property set to -1, and a previousIsIntersecting property set to false.
- %target.`RegisteredIntersectionObservers$sl に %交差~observer登録 を付加する ◎ Append intersectionObserverRegistration to target’s internal [[RegisteredIntersectionObservers]] slot.
- 此れ.`ObservationTargets$sl に %target を付加する ◎ Add target to this’s internal [[ObservationTargets]] slot.
- `root$m の`閲覧文脈$における`~event-loop$の反復を~scheduleする ◎ Schedule an iteration of the event loop in the root's browsing context.
- `unobserve(target)@m
-
被呼出時には、次を走らす: ◎ ↓
- %target.`RegisteredIntersectionObservers$sl から[ `~observer$rp ~prop ~EQ 此れ ]を満たす`交差~observer登録$を除去する ◎ Remove the IntersectionObserverRegistration record whose observer property is equal to this from target’s internal [[RegisteredIntersectionObservers]] slot.
- 此れ.`ObservationTargets$sl から %target を除去する ◎ Remove target from this’s internal [[ObservationTargets]] slot.
- 注記: `MutationObserver$I は `unobserve()$m を実装しない。 `unobserve()$m は、 `IntersectionObserver$I 用に,遅延読込みの利用事例に取組むためにある — その事例では、 %target が可視になった時点で追跡する必要もなくなるので。 すべての`~target$を `disconnect()$m した上で,必要なものを `observe()$m するときや、各 `~target$ごとに別々の `IntersectionObserver$I を作成するときは、より仕事が要ることになる。 ◎ Note: MutationObserver does not implement unobserve(). For IntersectionObserver, unobserve() addresses the lazy-loading use case. After target becomes visible, it does not need to be tracked. It would be more work to either disconnect() all targets and observe() the remaining ones, or create a separate IntersectionObserver for each target.
- `disconnect()@m
-
被呼出時には、次を走らす: ◎ ↓
- 此れ.`ObservationTargets$sl 内の ~EACH( %target ) に対し ⇒ %target.`RegisteredIntersectionObservers$sl から[ `~observer$rp ~prop ~EQ 此れ ]を満たす`交差~observer登録$を除去する
- 此れ.`ObservationTargets$sl を空にする ◎ ↑
- `takeRecords()@m
-
被呼出時には、次を走らす: ◎ ↓
- %~queue ~LET 此れ.`QueuedEntries$sl の複製 ◎ Let queue be a copy of this’s internal [[QueuedEntries]] slot.
- 此れ.`QueuedEntries$sl を空にする ◎ Clear this’s internal [[QueuedEntries]] slot.
- ~RET %~queue ◎ Return queue.
- `root@m
- 取得子は、[ 此れが`暗黙的な~root$を利用しているならば ~NULL / ~ELSE_ 此れが`交差~root$として利用している`要素$ ]を返す。 ◎ , of type Element, readonly, nullable ◎ The root Element to use for intersection, or null if the observer uses the implicit root.
- `rootMargin@m
-
取得子は、此れの`交差~root$の限界~boxの各~辺に適用される 一連の~offsetを,下に述べるように文字列に直列化した結果を返す。 これらの~offsetは:
- 交差域を計算する際に,その~boxを実質的に拡げる/狭めるために利用される。
- 適用されるのは、`~target$が`交差~root$と同じ`互いに関係するかつ生成元も類似する閲覧文脈~群$に属する場合に限られる。
-
一連の~offsetを直列化するときは、此れ.`rootMargin$sl 内の各 成分を次にしたがって文字列~化した結果を,順に~space区切りで連結する:
- ~pixel長さは[ 成分の数†, `px^l ]の並びにする
- 百分率は[ 成分の数†, `%^l ]の並びにする
【† その数を表現する 10 進記数法による文字列であろうが、詳細は規定されていない。 (`~CSS成分~値を直列化する$手続きに従う?) 】
結果と[ 此れの構築-時に渡された %options の `rootMargin$mb ]とが一致することは、保証されないことに注意。 %options にて `rootMargin$mb を省略した場合の結果は `0px 0px 0px 0px^l になる。
◎ On getting, return the result of serializing the elements of [[rootMargin]] space-separated, where pixel lengths serialize as the numeric value followed by "px", and percentages serialize as the numeric value followed by "%". Note that this is not guaranteed to be identical to the options.rootMargin passed to the IntersectionObserver constructor. If no rootMargin was passed to the IntersectionObserver constructor, the value of this attribute is "0px 0px 0px 0px". - `thresholds@m
- 取得子は、[ 此れの構築-時に渡された %options 引数の `threshold$mb ]内の一連の~thresholdを昇順で~sortした結果の~listを返す — `threshold$mb が供されていなかった場合、 1 個の 0 のみからなる~listになる。 各~thresholdは、此れが~observeしている各~targetの限界~box区画の交差~比率と比較され、ある~targetのそれが いずれかの~thresholdを横切ったとき,対する通知が生成される。 ◎ , of type FrozenArray<double>, readonly ◎ A list of thresholds, sorted in increasing numeric order, where each threshold is a ratio of intersection area to bounding box area of an observed target. Notifications for a target are generated when any of the thresholds are crossed for that target. If no options.threshold was provided to the IntersectionObserver constructor, the value of this attribute will be [0].
`IntersectionObserver$I ~obj %O の `交差~root@ は、[ %O の `root$m 属性の値 ~NEQ ~NULL ならば それ / ~ELSE_ `~top-level閲覧文脈$の`文書$~node ]である。 後者の場合の文書~nodeは `暗黙的な~root@ と呼ばれる。 ◎ The intersection root for an IntersectionObserver is the value of its root attribute, or else the top-level browsing context’s document node (referred to as the implicit root) if the root attribute is null.
`IntersectionObserver$I ~obj %O の `~root交差~矩形@ は、各~targetが交差しているかどうか検査するときに利用する矩形であり,次に従って与えられる: ◎ The root intersection rectangle for an IntersectionObserver is the rectangle we’ll use to check against the targets.
- %~root ~LET %O の`交差~root$ ◎ ↓
-
%~root矩形 ~LET %~root に応じて,次で与えられる矩形:
- `暗黙的な~root$である場合 ◎ If the intersection root is the implicit root,
- %~root の表示域 ◎ it’s the viewport’s size.
- %~root の~overflowが~clipされている場合 ◎ If the intersection root has an overflow clip,
- %~root の`内容~区画$ ◎ it’s the element’s content area.
- その他 ◎ Otherwise,
- %~root 上で `getBoundingClientRect()$m ~algoを走らせた結果 ◎ it’s the result of running the getBoundingClientRect() algorithm on the intersection root.
-
~IF[ `~target$と %~rootは 同じ `互いに関係するかつ生成元も類似する閲覧文脈~群$に属する ] ⇒ %~root矩形 ~SET %~root矩形 の各~辺を %O.`rootMargin$sl 内の 4 個の~offset値に則って,~CSSの `margin$p ~propに類似する方式で拡幅した結果 — すなわち:
- 正の長さは外方への~offsetを指示する。
- 値は順に,[ 上端, 右端, 下端, 左端 ]辺が~offsetされる量を指示する。
- 百分率は、~~元の矩形の横幅†を基準に解決する。 【†~layoutが縦組みの場合は、縦幅?】
- ~RET %~root矩形
注記: `rootMargin$m が適用されるのは、`交差~root$ 自身に限られる。 `~target$`要素$が`交差~root$以外の ある先祖の区画~内に~clipされる場合でも、その~clipingは `rootMargin$m からは影響されない。 ◎ Note: rootMargin only applies to the intersection root itself. If a target Element is clipped by an ancestor other than the intersection root, that clipping is unaffected by rootMargin.
注記: `~root交差~矩形$は、`~pinch-zoom$からは影響されない — ~pinch-zoomの主旨は、~layoutは変えずに,拡大鏡の様に動作することにあるので。 ◎ Note: Root intersection rectangle is not affected by pinch zoom and will report the unadjusted viewport, consistent with the intent of pinch zooming (to act like a magnifying glass and NOT change layout.)
`~root~marginを構文解析する@ ときは、所与の ( 文字列 %~margin文字列 ) に対し,次を走らす — これは、それぞれが[ ~pixel長さ, または百分率 ]のいずれかである 4 個の値からなる~list, または `失敗^i を返す: ◎ To parse a root margin from an input string marginString, returning either a list of 4 pixel lengths or percentages, or failure:
- %~token~list ~LET %~margin文字列 から`成分~値~listを構文解析-$した結果 ◎ Parse a list of component values marginString, storing the result as tokens.
- %~token~list からすべての`空白~token$を除去する ◎ Remove all whitespace tokens from tokens.
- ~IF[ %~token~list の長さ ~NIN { 1, 2, 3, 4 } ] ⇒ ~RET `失敗^i ◎ If the length of tokens is 0 or greater than 4, return failure.
- %結果 ~LET 空~list
-
%~token~list 内の ~EACH( %token ) に対し: ◎ Replace each token in tokens:
- ~IF[ %token は`絶対~長さ$による `dimension$t ~tokenである ] ⇒ %結果 に %token に等価な~pixel長さを付加する ◎ If token is an absolute length dimension token, replace it with a an equivalent pixel length.
- ~ELIF[ %token は `percentage$t ~tokenである ] ⇒ %結果 に %token に等価な百分率を付加する ◎ If token is a <percentage> token, replace it with an equivalent percentage.
- ~ELSE ⇒ ~RET `失敗^i ◎ Otherwise, return failure.
- ~WHILE[ %結果 の長さ ~LT 3 ] ⇒ %結果 に[ %結果 内の 1 個目の値の~~複製 ]付加する ◎ ↓
- ~IF[ %結果 の長さ ~EQ 3 ] ⇒ %結果 に[ %結果 内の 2 個目の値の~~複製 ]を付加する ◎ If there is one element in tokens, append three duplicates of that element to tokens. If there is two elements are tokens, append a duplicate of each element to tokens. If there are three elements in tokens, append a duplicate of the second element to tokens.
- ~RET %結果 ◎ Return tokens.
2.3. `IntersectionObserverEntry^I ~interface
[Constructor(`IntersectionObserverEntryInit$I %intersectionObserverEntryInit)] interface `IntersectionObserverEntry@I { readonly attribute `DOMHighResTimeStamp$I `time$m; readonly attribute `DOMRectReadOnly$I `rootBounds$m; readonly attribute `DOMRectReadOnly$I `boundingClientRect$m; readonly attribute `DOMRectReadOnly$I `intersectionRect$m; readonly attribute boolean `isIntersecting$m; readonly attribute double `intersectionRatio$m; readonly attribute `Element$I `target$m; }; dictionary `IntersectionObserverEntryInit@I { required `DOMHighResTimeStamp$I `time@mb; required `DOMRectInit$I `rootBounds@mb; required `DOMRectInit$I `boundingClientRect@mb; required `DOMRectInit$I `intersectionRect@mb; required boolean `isIntersecting@mb; required double `intersectionRatio@mb; required `Element$I `target@mb; };
【 個々の交差~event通知は、この~interfaceが表現する。 】
`IntersectionObserverEntry$I ~obj %~entry を `生成した~observer@ とは、 %~entry が`~IntersectionObserverEntryを~queueする$手続きにて構築されたならば,その手続きの入力に与えられた `IntersectionObserver$I ~objを指す。 他の場合は未定義とする。
【 この用語は、以下の記述を明確化するためにこの訳に導入している。 `生成した~observer$が未定義の場合 — 例えば~scriptから `IntersectionObserverEntry()$m 構築子を呼出して作成されるものなど — の挙動は、ここには述べられていない(が,おそらく、単に渡された `IntersectionObserverEntryInit$I 引数で各種~属性が初期化されるだけであろう)。 】【 この節の “真の” 規範的な記述は、上述の手続きを含む`処理~model節$に定義される。 】
- `boundingClientRect@m
- 此れの `target$m 上で `getBoundingClientRect()$m ~algoを走らせた結果になる。 ◎ A DOMRectReadOnly obtained by running the getBoundingClientRect() algorithm on the target.
- `intersectionRect@m
-
次に挙げる矩形すべての交差域(共通域)になる:
- 此れの `boundingClientRect$m
- 次を満たす各~要素の~cliping矩形 ⇒ [ 此れを`生成した~observer$の`交差~root$の子孫である ]~AND[ 此れの `target$m の先祖である ]
- 此れを`生成した~observer$の`~root交差~矩形$
この値は、此れを`生成した~observer$の`~root交差~矩形$内で実際に可視になる, `target$m の部位を表現する。
◎ boundingClientRect, intersected by each of target's ancestors' clip rects (up to but not including root), intersected with the root intersection rectangle. This value represents the portion of target actually visible within the root intersection rectangle. - `isIntersecting@m
- 此れの `target$m が此れの `root$m に交差しているならば ~T / ~ELSE_ ~F を返す。 ◎ True if the target intersects with the root; false otherwise.\
- この~flagにより、交差~矩形の面積が 0 であるような交差(辺が接しているか, `boundingClientRect$m の面積が 0 の場合に起こる)においても,交差するように遷移したか, その逆に遷移したかを判別-可能になる。 ◎ This flag makes it possible to distinguish between an IntersectionObserverEntry signalling the transition from intersecting to not-intersecting; and an IntersectionObserverEntry signalling a transition from not-intersecting to intersecting with a zero-area intersection rect (as will happen with edge-adjacent intersections, or when the boundingClientRect has zero area).
- `intersectionRatio@m
- 此れの `boundingClientRect$m の面積 %面積 ~GT 0 ならば、 ( 此れの `intersectionRect$m の面積 ~DIV %面積 ) になる。 他の場合、此れの `isIntersecting$m に応じて[ ~T ならば 1 / ~F ならば 0 ]になる。 ◎ If the boundingClientRect has non-zero area, this will be the ratio of intersectionRect area to boundingClientRect area. Otherwise, this will be 1 if the isIntersecting is true, and 0 if not.
- `rootBounds@m
- `target$m が[ 此れを`生成した~observer$の`交差~root$ ]と同じ `互いに関係するかつ生成元も類似する閲覧文脈~群$に属するならば、此れを`生成した~observer$の`~root交差~矩形$になる。 ~ELSE_ ~NULL になる。 ◎ If target belongs to the same unit of related similar-origin browsing contexts as the intersection root, this will be the root intersection rectangle. Otherwise, this will be null. Note that if the target is in a different browsing context than the intersection root, this will be in a different coordinate system than boundingClientRect and intersectionRect.
- ~targetが`交差~root$と異なる`閲覧文脈$内にある場合の結果は、 `boundingClientRect$m, `intersectionRect$m とは異なる座標系に属することに注意。 ◎ ↑
- `target@m
- 此れを`生成した~observer$の`交差~root$との交差が変化した`要素$を返す。 ◎ The Element whose intersection with the intersection root changed.
- `time@m
- 交差が記録された時刻を,[ 此れを`生成した~observer$に結付けられている大域~obj ]の`時刻起点$を基準にして表す `DOMHighResTimeStamp$I 型~値を返さ~MUST。 ◎ The attribute must return a DOMHighResTimeStamp that corresponds to the time the intersection was recorded, relative to the time origin of the global object associated with the IntersectionObserver instance that generated the notification.
2.4. `IntersectionObserverInit^I ~dictionary
dictionary `IntersectionObserverInit@I { `Element$I? `root$mb = null; DOMString `rootMargin$mb = "0px"; (double or sequence<double>) `threshold$mb = 0; };
- `root@mb
- 利用する`交差~root$を与える。 省略時( ~NULL )には、`暗黙的な~root$が利用される。 ◎ The root to use for intersection. If not provided, use the implicit root.
- `rootMargin@mb
- ~CSS `margin$p ~propと類似的に、[ 各 成分が`絶対~長さ$または百分率を表す ]ような 1 〜 4 個の成分からなる文字列として,`交差~root$に適用する~marginを与える。 ◎ Similar to the CSS margin property, this is a string of 1-4 components, each either an absolute length or a percentage.
-
値の例と 適用される~margin 値 上端 右端 下端 左端 `5px^l `5px^v `5px^v `5px^v `5px^v `5px 10px^l `5px^v `10px^v `5px^v `10px^v `-10px 5px 8px^l `-10px^v `5px^v `8px^v `5px^v `-10px -5px 5px 8px^l `-10px^v `-5px^v `5px^v `8px^v "5px" // all margins set to 5px "5px 10px" // top & bottom = 5px, right & left = 10px "-10px 5px 8px" // top = -10px, right & left = 5px, bottom = 8px "-10px -5px 5px 8px" // top = -10px, right = -5px, bottom = 5px, left = 8px
- `threshold@mb
- ~callbackを誘発するための,一連の~thresholdからなる~listを与える。 `intersectionRect$m 区画の比率が[ いずれかの~threshold~以上から それ未満に変化した / その逆に変化した ]とき、~callbackが呼出されることになる。 ◎ List of threshold(s) at which to trigger callback. callback will be invoked when intersectionRect’s area changes from greater than or equal to any threshold to less than that threshold, and vice versa.
- どの~thresholdも範囲 { 0 〜 1.0 } に入ってい~MUST。 各 ~thresholdは、 `~target$上で `getBoundingClientRect()$m ~algoを走らせて得られる矩形~区画の可視率を表現する。 ◎ Threshold values must be in the range of [0, 1.0] and represent a percentage of the area of the rectangle produced by running the getBoundingClientRect() algorithm on the target.
- 注記: 値 0.0 は、実質的に, “非~zero個の~pixel” を表す。 【すなわち、少しでも交差しているかどうか。】 ◎ Note: 0.0 is effectively "any non-zero number of pixels".
3. 処理~model
この節では、~UAが`交差~observer$ ~APIを実装するときに とら~MUST手続きを要旨する。 ◎ This section outlines the steps the user agent must take when implementing the Intersection Observer API.
3.1. 各種 内部~slotの定義
3.1.1. 文書
各 `文書$には `交差~observer~task処理待ち~flag@ ( IntersectionObserverTaskQueued flag ) が結付けられ、初期~時は ~OFF にされる。 ◎ Each Document has an IntersectionObserverTaskQueued flag which is initialized to false.
【 この~flagは、いっときに生じた一連の交差が 1 回の通知に集約されるように処理を制御する。 交差が生じたとき(それは、~event-loop処理の中で`交差~observationsの更新~手続きを走らす$ことにより検出される)、最終的に `交差~observerたちに通知する$~taskが~queueされる。 その~task(それは、~observerの構築子に渡された %callback を呼出して~scriptに交差を通知する)が実際に走り始めるまで、この~flagは ~ON にされる。 その間に検出された新たな交差の通知は、新たな~taskを~queueすることなく留め置かれ,先送りされることになる。 言い換えれば、この~flagは,ある程度の最適化の裁量を~UAに与えるためにあるように見受けられる。 】
3.1.2. 要素
各 `要素$は、 `RegisteredIntersectionObservers@sl 内部~slotを持ち,初期~時は空~listにされ~MUST。 この~listは、 `交差~observer登録@ と呼ばれる~recordたちを保持する。 その各~recordは、次の~propからなる:
- `~observer@rp
- 【当の要素を~observeしている】 `IntersectionObserver$I を保持する。
- `前回の~threshold~index@rp
- 範囲 { −1 〜 `~observer$rp の `thresholds$m の長さ } に入る整数を保持する。
- 【 −1 は初期~値。 0 以上の値は、一部の特殊な事例を除き,要素の直近の交差~比率が 一連の~thresholdで区切られる何番目の区間に入っているかを指示する。 0 は 最小の~threshold未満, 最大~値は 最大~threshold以上の区間に対応する。 】
- `前回に交差あり@rp
- 真偽値を保持する。
- 【 要素が交差しているかどうかを指示する。 その変化を追跡するためにあり、変化-時には通知が生成される。 】
3.1.3. `IntersectionObserver^I
各 `IntersectionObserver$I ~obj %O は、次に挙げる内部~slotを持つ:
- `QueuedEntries@sl
- 初期~時は空~listとする。
- 【 %O が~observeしている~targetたちにおける交差の変化を表現する各 通知を,内部的に保持する。 】
- `ObservationTargets@sl
- 初期~時は空~listとする。
- 【 %O が~observeしている~targetたちを,内部的に保持する。 順序は、~targetを引数に %O の `observe()$m が~callされた順になる。 】
- `callback@sl
- `IntersectionObserver()$m にて初期化される。
- 【 %O の構築-時に渡された %callback を内部的に保持する。 】
- `rootMargin@sl
- 4 個の~pixel長さまたは百分率からなる~list。
- 【 %O の `rootMargin$m が表現する 4 辺の~offsetを内部的に保持する。 】
3.2. 各種~algo
3.2.1. 交差~observer~taskを~queueする
`文書$ %文書 用に `交差~observer~taskを~queueする@ ときは、次を走らす: ◎ To queue an intersection observer task for a Document document, run these steps:
- ~IF[ %文書 の`交差~observer~task処理待ち~flag$ ~EQ ~ON ] ⇒ ~RET ◎ If document’s IntersectionObserverTaskQueued flag is set to true, return.
- %文書 の`交差~observer~task処理待ち~flag$ ~SET ~ON ◎ Set document’s IntersectionObserverTaskQueued flag to true.
- %~task ~LET 次を走らす~task ⇒ %文書 用の`交差~observerたちに通知する$ ◎ ↓
-
%文書 の`~event-loop$に %~task を`~queueする$
【 %文書 が属する閲覧文脈の~event-loop? 利用する`~task源$は`利用者~対話~task源$? 】
◎ Queue a task to the document’s event loop to notify intersection observers.
3.2.2. 交差~observerたちに通知する
`文書$ %文書 用の `交差~observerたちに通知する@ ときは、次を走らす: ◎ To notify intersection observers for a Document document, run these steps:
- %文書 の`交差~observer~task処理待ち~flag$ ~SET ~OFF ◎ Set document’s IntersectionObserverTaskQueued flag to false.
- %通知-~list ~LET 次を満たす `IntersectionObserver$I すべてからなる~list ⇒ その `root$m 【 `交差~root$?】 は %文書 の~DOM木内にある ◎ Let notify list be a list of all IntersectionObservers whose root is in the DOM tree of document.
-
%通知-~list 内の ~EACH( %~observer ) に対し: ◎ For each IntersectionObserver object observer in notify list, run these steps:
- ~IF[ %~observer.`QueuedEntries$sl は空である ] ⇒ ~CONTINUE ◎ If observer’s internal [[QueuedEntries]] slot is empty, continue.
- %~queue ~LET %~observer.`QueuedEntries$sl の複製 ◎ Let queue be a copy of observer’s internal [[QueuedEntries]] slot.
- %~observer.`QueuedEntries$sl を空にする ◎ Clear observer’s internal [[QueuedEntries]] slot.
-
次を与える下で, %~observer.`callback$sl を呼出す:
- `~callback this 値$ ~SET %~observer
- 引数~list ~SET ( %~queue, %~observer )
この段で例外が投出された場合は、その`例外を報告-$する 【この手続き自体は継続する】
◎ Invoke callback with queue as the first argument and observer as the second argument and callback this value. If this throws an exception, report the exception.
3.2.3. `IntersectionObserverEntry^I を~queueする
`IntersectionObserver$I %~observer 用に `~IntersectionObserverEntryを~queueする@ ときは、所与の ⇒# %文書 (`文書$ ), %time ( `DOMHighResTimeStamp$I ), %rootBounds ( `DOMRect$I ), %boundingClientRect ( `DOMRect$I ), %intersectionRect ( `DOMRect$I ), %isIntersecting ( `boolean^I ), %target ( `要素$ ) ◎終 に対し,次を走らす: ◎ To queue an IntersectionObserverEntry for an IntersectionObserver observer, given a Document document; DOMHighResTimeStamp time; DOMRects rootBounds, boundingClientRect, intersectionRect, and isIntersecting flag; and an Element target; run these steps:
- %~observer.`QueuedEntries$sl に,次のように構築された 新たな `IntersectionObserverEntry$I を付加する ⇒# `time$m ~SET %time, `rootBounds$m ~SET %rootBounds, `boundingClientRect$m ~SET %boundingClientRect, `intersectionRect$m ~SET %intersectionRect, `isIntersecting$m ~SET %isIntersecting, `target$m ~SET %target ◎ Construct an IntersectionObserverEntry, passing in time, rootBounds, boundingClientRect, intersectionRect, isIntersecting, and target. ◎ Append it to observer’s internal [[QueuedEntries]] slot.
- %文書 用に`交差~observer~taskを~queueする$ ◎ Queue an intersection observer task for document.
3.2.4. ~target要素と~rootとの交差域を算出する
`交差域を算出する@ ときは、所与の ( `~target$ %~target, ある~observerの`交差~root$ %~root ) に対し,次を走らす: ◎ To compute the intersection between a target and the observer’s intersection root, run these steps:
- %交差~矩形 ~LET %~target 上で `getBoundingClientRect()$m ~algoを走らせた結果 ◎ Let intersectionRect be the result of running the getBoundingClientRect() algorithm on the target.
- %容器 ~LET %~target の`包含塊$ 【を生成している要素】 ◎ Let container be the containing block of the target.
-
~WHILE[ %容器 ~NEQ %~root ]: ◎ While container is not the intersection root:
- %交差~矩形 ~SET %交差~矩形 を %容器 の座標空間に写像した結果 ◎ Map intersectionRect to the coordinate space of container.
- ~IF[ %容器 の~overflowは~clipされている ]~OR[ %容器 は~CSS `clip-path$p ~propにより~clipされている ] ⇒ %交差~矩形 ~SET %交差~矩形 を %容器 で~clipした結果 ◎ If container has overflow clipping or a css clip-path property, update intersectionRect by applying container’s clip.
-
~IF[ %容器 は ある`入子の閲覧文脈$ %C の~root要素である ]:
- %容器 ~SET %C を入子にしている`閲覧文脈~容器$
- %交差~矩形 ~SET %交差~矩形 を %C の`表示域$で~clipした結果
- ~ELSE ⇒ %容器 ~SET %容器 の`包含塊$ ◎ ↑
- %交差~矩形 ~SET %交差~矩形 を %~root の座標空間に写像した結果 ◎ Map intersectionRect to the coordinate space of the intersection root.
- %交差~矩形 ~SET %交差~矩形 と`~root交差~矩形$との交差域 ◎ Update intersectionRect by intersecting it with the root intersection rectangle.
- %交差~矩形 ~SET %交差~矩形 を[ %~target を包含している`文書$の表示域の座標空間 ]に写像した結果 ◎ Map intersectionRect to the coordinate space of the viewport of the Document containing the target.
3.2.5. 交差~observationsを更新する手続き
`文書$ %文書 に対する `交差~observationsの更新~手続きを走らす@ ときは、所与の時刻印 %時刻 に対し,次を走らす: ◎ To run the update intersection observations steps for a Document document given a timestamp time, run these steps:
- %~observer~list ~LET 次を満たす `IntersectionObserver$I ~objすべてからなる~list ⇒ `root$m 【 `交差~root$?】 は %文書 の~DOM木内にある ◎ Let observer list be a list of all IntersectionObservers whose root is in the DOM tree of document.
-
%~observer~list 内の ~EACH( %~observer ) に対し: ◎ For each observer in observer list:
- %~root ~LET %~observer の`交差~root$ ◎ ↓
- %~root境界 ~LET %~observer の`~root交差~矩形$ ◎ Let rootBounds be observer’s root intersection rectangle.
-
%~observer.`ObservationTargets$sl 内の ~EACH( %target ) に対し: ◎ For each target in observer’s internal [[ObservationTargets]] slot, processed in the same order that observe() was called on each target:
- ~IF[ %~root は`暗黙的な~root$でない ]~AND[[ %target は %~root と同じ`文書$ 内にない ]~OR[ %target は %~root の`包含塊~連鎖$内の子孫ではない ]] ⇒ ~CONTINUE ◎ If the intersection root is not the implicit root and target is not a descendant of the intersection root in the containing block chain, skip further processing for target. ◎ If the intersection root is not the implicit root, and target is not in the same Document as the intersection root, skip further processing for target.
- %~target矩形 ~LET %target 上で `getBoundingClientRect()$m ~algoを走らせた結果 ◎ Let targetRect be a DOMRectReadOnly obtained by running the getBoundingClientRect() algorithm on target.
- %交差~矩形 ~LET `交差域を算出する$( %target, %~root ) ◎ Let intersectionRect be the result of running the compute the intersection algorithm on target. ◎ Let targetArea be targetRect’s area. ◎ Let intersectionArea be intersectionRect’s area.
- %交差あり ~LET[ %~target矩形 と %~root境界 は交差するならば ~T / ~ELSE_ ~F ] ⇒ ここでは、辺どうしが接する場合も含め,互いの区画が重なるならば、交差域の面積が 0 ( %~root境界 や %~target矩形 の面積が 0 の場合など)であっても交差するとする。 ◎ Let isIntersecting be true if targetRect and rootBounds intersect or are edge-adjacent, even if the intersection has zero area (because rootBounds or targetRect have zero area); otherwise, let isIntersecting be false.
- %交差~比率 ~SET [ %~target矩形 の面積 ~GT 0 ならば ( %交差~矩形 の面積 ~DIV %~target矩形 の面積 ) / ~ELSE_ %交差あり ~EQ ~T ならば 1 / ~ELSE_ 0 ] ◎ If targetArea is non-zero, let intersectionRatio be intersectionArea divided by targetArea. Otherwise, let intersectionRatio be 1 if isIntersecting is true, or 0 if isIntersecting is false.
- %~threshold~list ~LET %~observer の `thresholds$m ◎ ↓
- %~threshold~index ~LET %~threshold~list 内の~entryに[ ~entryの値 ~GT %交差~比率 ]を満たすものが[ あれば それらのうち %~threshold~list 内で最初の~entryの~index / なければ %~threshold~list の長さ ] ◎ Let thresholdIndex be the index of the first entry in observer.thresholds whose value is greater than intersectionRatio, or the length of observer.thresholds if intersectionRatio is greater than or equal to the last entry in observer.thresholds.
- %交差~observer登録 ~LET %target.`RegisteredIntersectionObservers$sl 内の[ `~observer$rp ~prop ~EQ %~observer ]を満たす`交差~observer登録$ ◎ Let intersectionObserverRegistration be the IntersectionObserverRegistration record in target’s internal [[RegisteredIntersectionObservers]] slot whose observer property is equal to observer.
- %前回の~threshold~index ~LET %交差~observer登録 の`前回の~threshold~index$rp ◎ Let previousThresholdIndex be the intersectionObserverRegistration’s previousThresholdIndex property.
- %前回に交差あり ~LET %交差~observer登録 の`前回に交差あり$rp ◎ Let previousIsIntersecting be the intersectionObserverRegistration’s previousIsIntersecting property.
- ~IF[ %~threshold~index ~NEQ %前回の~threshold~index ]~OR[ %交差あり ~NEQ %前回に交差あり ] ⇒ 次を与える下で、 %~observer 用に`~IntersectionObserverEntryを~queueする$ ⇒# %文書, %時刻, %~root境界, %~target矩形, %交差~矩形, %交差あり, %target ◎ If thresholdIndex does not equal previousThresholdIndex or if isIntersecting does not equal previousIsIntersecting, queue an IntersectionObserverEntry, passing in observer, time, rootBounds, boundingClientRect, intersectionRect, isIntersecting, and target.
- %交差~observer登録 の ⇒# `前回の~threshold~index$rp ~SET %~threshold~index, `前回に交差あり$rp ~SET %交差あり ◎ Assign threshold to intersectionObserverRegistration’s previousThresholdIndex property. ◎ Assign isIntersecting to intersectionObserverRegistration’s previousIsIntersecting property.
3.3. `IntersectionObserver^I の存続期間
`IntersectionObserver$I %O は、次の両~条件とも満たされない限り,生き残り続ける: ◎ An IntersectionObserver will remain alive until both of these conditions hold:
- どの~scriptも %O を参照していない。 ◎ There are no scripting references to the observer.
- %O が~observeしている~targetはない。 ◎ The observer is not observing any targets.
`IntersectionObserver$I %O は、次のいずれかが生じるまで, `~target$ %target を~observeし続ける: ◎ An IntersectionObserver will continue observing a target until any of the following occurs:
- %O 上で `unobserve(target)$m が~callされたとき。 ◎ unobserve(target) is called on the target.
- %O 上で `disconnect()$m が~callされたとき。 ◎ disconnect() is called.
- %target が~DOMから削除されたとき。 ◎ The target Element is deleted.
- %O の`交差~root$が~DOMから削除されたとき。 ◎ The observer’s intersection root is deleted.
3.4. 外部 仕様との統合
3.4.1. ~HTMLの~event-loop処理~model
`交差~observer$ 処理~段は、~HTMLに規定される`~event-loop処理~model$における,`描画を更新する$ 段の中で行われるべきである — その `~fullscreen化~手続き$を走らす段と `~animation~frame~callbackを走らす$段の合間に。 ◎ An Intersection Observer processing step should take place during the "Update the rendering" steps, after step 9, run the fullscreen rendering steps, and before step 10, run the animation frame callbacks, in the in the HTML Processing Model.
【 WHATWG ~HTML仕様には、すでに統合されている — その仕様では、実際には,合間ではなく 直後の段にされている。 】
この段は、次で与えられる: ◎ This step is:
- %文書たち 内の ~EACH( `全部的に作動中$にある`文書$ %文書 ) に対し ⇒ %文書 に対する`交差~observationsの更新~手続きを走らす$ ◎ For each fully active Document in docs, Run the update intersection observations steps for each IntersectionObserver whose root is in the DOMtree of that Document.
謝辞
この仕様に技術的貢献や示唆を寄せられた すべての協力者たち に。 ◎ Special thanks to all the contributors for their technical input and suggestions that led to improvements to this specification.