1. 引言
Web 传统的计算位置的机制依赖于对 DOM 状态的显式查询,这些查询已知会导致(昂贵的)样式重新计算和布局,并且由于持续轮询这些信息,经常成为显著性能开销的来源。
人们已经形成了一套依赖于这些行为的通用实践,包括(但不限于):
-
构建自定义的 DOM 和数据预加载与延迟加载。
-
实现数据绑定的高性能滚动列表,以加载和渲染数据集的子集。这些列表是移动端交互的核心惯用语。
-
计算元素可见性。特别是,广告网络现在要求上报广告的“可见性”以实现展示价值变现。这导致许多网站滥用滚动事件处理程序(导致滚动卡顿)、同步触发布局读回(在 rAF 循环中引起不必要的关键工作),并不得不诉诸基于插件的奇异解决方案来计算“真实”的元素可见性(伴随着插件架构带来的所有相关开销)。
这些用例有几个共同属性:
-
它们可以表示为关于单个元素相对于其他元素(或全局视口)状态的被动“查询”。
-
它们没有严格的延迟要求;换句话说,这些信息可以异步(例如从另一个线程)交付而不会产生负面影响。
-
现有的网络平台功能组合对它们的支持很差,尽管它们被广泛使用,却需要开发者付出极大的努力。
一个明确的非目标是提供关于实际显示内容的像素级精确信息(鉴于滤镜、WebGL 和其他功能,在某些浏览器架构中很难高效获取这些信息)。在所有这些场景中,即使信息有轻微延迟且没有完美的合成结果数据,信息也是有用的。
Intersection Observer API 通过为开发者提供一种新方法,以异步查询元素相对于其他元素或全局视口的位置,解决了上述问题。异步交付消除了对昂贵的 DOM 和样式查询、持续轮询以及使用自定义插件的需求。通过移除对这些方法的需求,它使应用程序能够显著降低其 CPU、GPU 和能源成本。
var observer= new IntersectionObserver( changes=> { for ( const changeof changes) { console. log( change. time); // Timestamp when the change occurred console. log( change. rootBounds); // Unclipped area of root console. log( change. boundingClientRect); // target.getBoundingClientRect() 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. Intersection Observer (交叉观察器)
Intersection Observer API 使开发者能够了解 目标 (target) DOM 元素相对于交叉根 (intersection root) 的可见性和位置。
2.1. The IntersectionObserverCallback (IntersectionObserverCallback)
callback =IntersectionObserverCallback undefined (sequence <IntersectionObserverEntry >,entries IntersectionObserver );observer
当目标与交叉根的交叉发生变化时,此回调将按照处理模型被调用。
2.2. The IntersectionObserver interface (IntersectionObserver 接口)
IntersectionObserver 接口可用于观察交叉根与一个或多个目标 Element 之间交叉情况的变化。
IntersectionObserver 的 交叉根 (intersection root) 是其 root 属性的值(如果该属性非 null);否则,它是顶级浏览上下文的 document 节点,称为 隐式根 (implicit root)。
具有非 null root 的 IntersectionObserver 被称为 显式根观察器 (explicit root observer),它可以观察目标 Element 中任何在包含块链中属于 root 后代的元素。具有 null root 的 IntersectionObserver 被称为 隐式根观察器 (implicit root observer)。隐式根观察器的有效目标包括顶级浏览上下文中的任何 Element,以及任何处于顶级浏览上下文后代浏览上下文列表中任何嵌套浏览上下文中的 Element。
在处理隐式根观察器时,API 会区分:其相关设置对象的源与顶级源同源域的目标,称为 同源域目标 (same-origin-domain target);以及 跨源域目标 (cross-origin-domain target)。显式根观察器的任何目标也都是 同源域目标,因为目标必须与交叉根位于同一个 文档 中。
注意:在 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)-
执行 观察目标元素 算法,提供 this 和 target。
unobserve(target)-
执行 取消观察目标元素 算法,提供 this 和 target。
注意:
MutationObserver不实现unobserve()。对于IntersectionObserver,unobserve()解决了延迟加载用例。在 target 变得可见后,就不再需要对其进行跟踪。如果disconnect()所有 targets 然后observe()剩余的目标,或者为每个 target 创建一个单独的IntersectionObserver,工作量会更大。 disconnect()-
对于 this 内部
[[ObservationTargets]]槽中的每个 target:-
从 target 内部的
[[RegisteredIntersectionObservers]]槽中移除其observer属性等于 this 的IntersectionObserverRegistration记录。 -
从 this 内部的
[[ObservationTargets]]槽中移除 target。
-
takeRecords()-
-
设 queue 为 this 内部
[[QueuedEntries]]槽的副本。 -
清除 this 内部
[[QueuedEntries]]槽。 -
返回 queue。
-
root,类型为(Element or Document),只读,可为空-
传递给
IntersectionObserver构造函数的root,如果未提供则为null。 rootMargin,类型为 DOMString,只读-
应用于根交叉矩形的偏移量,有效地扩大或缩小用于计算交叉的框。这些偏移量仅在处理同源域目标时应用;对于跨源域目标,它们将被忽略。
获取时,返回将
[[rootMargin]]的元素以空格分隔序列化的结果,其中像素长度序列化为数值后跟“px”,百分比序列化为数值后跟“%”。注意,这不能保证与传递给IntersectionObserver构造函数的 options.rootMargin完全相同。如果未向IntersectionObserver构造函数传递rootMargin,则此属性的值为“0px 0px 0px 0px”。 scrollMargin,类型为 DOMString,只读-
偏移量应用于从交叉根到目标路径上的滚动端口 (scrollports),有效地扩大或缩小用于计算交叉的裁剪矩形。
获取时,返回将
[[scrollMargin]]的元素以空格分隔序列化的结果,其中像素长度序列化为数值后跟“px”,百分比序列化为数值后跟“%”。注意,这不能保证与传递给IntersectionObserver构造函数的 options.scrollMargin完全相同。如果未向IntersectionObserver构造函数传递scrollMargin,则此属性的值为“0px 0px 0px 0px”。 thresholds,类型为 FrozenArray<double>,只读-
阈值列表,按数值增加顺序排列,其中每个阈值是观察目标交叉面积与边界框面积之比。当目标的任何阈值被跨越时,就会为该目标生成通知。如果未向
IntersectionObserver构造函数提供 options.threshold,或者序列为空,则此属性的值将为 [0]。
如果 Element 的计算样式具有导致其内容被裁剪到元素内边距边缘的溢出属性,则该元素被定义为具有 内容裁剪 (content clip)。
IntersectionObserver 的 根交叉矩形 (root intersection rectangle) 是我们将用于与目标进行检查的矩形。
- 如果
IntersectionObserver是一个隐式根观察器, - 它将被视为根是顶级浏览上下文的
document,根据document的以下规则。 - 如果交叉根是一个
document, - 它是
document的视口大小(注意,此处理步骤仅在document完全激活时才能到达)。 - 否则,如果交叉根具有内容裁剪,
- 它是该元素的内边距区域。
- 否则,
- 它是获取交叉根边界框的结果。
在计算同源域目标的根交叉矩形时,矩形随后会根据 IntersectionObserver 的 [[rootMargin]] 槽中的偏移量进行扩展,方式类似于 CSS 的 margin 属性,四个值分别表示上、右、下和左边缘的偏移量,正长度表示向外偏移。百分比是相对于未扩展矩形的宽度进行解析的。
注意:rootMargin 仅应用于交叉根本身。如果目标 Element 被非交叉根的祖先裁剪,则该裁剪不受 rootMargin 的影响。
- 若要 应用滚动边距到滚动端口 (apply scroll margin to a scrollport)
-
在计算同源域目标的滚动端口交叉矩形时,矩形会根据
IntersectionObserver的[[scrollMargin]]槽中的偏移量进行扩展,方式类似于 CSS 的 margin 属性,四个值分别表示上、右、下和左边缘的偏移量,正长度表示向外偏移。百分比是相对于未扩展矩形的宽度进行解析的。这些偏移量仅在处理同源域目标时应用;对于跨源域目标,它们将被忽略。
注意:
scrollMargin会影响所有可滚动祖先(包括交叉根)对目标的裁剪。scrollMargin和rootMargin都会应用于可滚动的交叉根矩形。
注意:根交叉矩形和滚动端口交叉矩形不受缩放 (pinch zoom) 的影响,并将报告未经调整的视口,这与缩放的意图一致(即表现得像放大镜,而不会改变布局)。
若要从输入字符串 marginString 解析边距 (parse a margin)(根或滚动),返回 4 个像素长度或百分比的列表,或失败
-
解析组件值列表 marginString,将结果存储为 tokens。
-
从 tokens 中移除所有空格标记。
-
如果 tokens 的长度大于 4,则返回失败。
-
如果 tokens 中有零个元素,则将 tokens 设置为 ["0px"]。
-
替换 tokens 中的每个 token:
-
如果 token 是 <percentage> 标记,则将其替换为等效的百分比。
-
否则,返回失败。
-
如果 tokens 中有一个元素,则在该元素后面追加三个相同的元素。否则,如果 tokens 中有两个元素,则在该元素后面追加每个元素的副本。否则,如果 tokens 中有三个元素,则追加第二个元素的副本。
-
返回 tokens。
2.3. The IntersectionObserverEntry interface (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,只读-
通过获取
target的边界框而获得的DOMRectReadOnly。 intersectionRect,类型为 DOMRectReadOnly,只读-
boundingClientRect,与target的每个祖先的裁剪矩形(向上但不包含root)取交集,并与根交叉矩形取交集。该值代表target实际在根交叉矩形内可见的部分。 isIntersecting,类型为 boolean,只读-
如果
target与root交叉,则为 true;否则为 false。此标志使得区分以下两种情况成为可能:发出从交叉到不交叉转换信号的IntersectionObserverEntry;以及发出从不交叉到与零面积交叉矩形交叉转换信号的IntersectionObserverEntry(这会发生在边缘邻接交叉或boundingClientRect面积为零时)。 intersectionRatio,类型为 double,只读-
如果
boundingClientRect的面积不为零,则这将是intersectionRect面积与boundingClientRect面积之比。否则,如果isIntersecting为 true,则这将为 1,否则为 0。 rootBounds,类型为 DOMRectReadOnly,只读,可为空-
对于同源域目标,这将是根交叉矩形。否则,这将为
null。注意,如果目标与交叉根位于不同的浏览上下文中,这将处于与boundingClientRect和intersectionRect不同的坐标系中。 target,类型为 Element,只读time,类型为 DOMHighResTimeStamp,只读-
该属性必须返回一个
DOMHighResTimeStamp,它对应于记录交叉的时间,相对于与生成通知的 IntersectionObserver 实例关联的全局对象的时间原点。
2.4. The IntersectionObserverInit dictionary (IntersectionObserverInit 字典)
dictionary { (IntersectionObserverInit Element or Document )?root =null ;DOMString rootMargin = "0px";DOMString scrollMargin = "0px"; (double or sequence <double >)threshold = 0; };
root,类型为(Element or Document),可为空,默认为nullrootMargin,类型为 DOMString,默认为"0px"-
类似于 CSS margin 属性,这是一个由 1-4 个组件组成的字符串,每个组件要么是绝对长度,要么是百分比。
"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 scrollMargin,类型为 DOMString,默认为"0px"-
类似于
rootMargin,这是一个由 1-4 个组件组成的字符串,每个组件要么是绝对长度,要么是百分比。有关示例,请参见上文的
rootMargin。 threshold,类型为(double or sequence<double>),默认为0-
触发回调的阈值列表。当 intersectionRect 的面积从大于或等于任何阈值变为小于该阈值时(反之亦然),将调用回调。
阈值必须在 [0, 1.0] 的范围内,并表示获取目标边界框所生成的矩形面积的百分比。
注意:0.0 实际上意味着“任何非零像素数”。
3. Processing Model (处理模型)
本节概述了用户代理在实现 Intersection Observer API 时必须采取的步骤。
3.1. Internal Slot Definitions (内部槽位定义)
3.1.1. Document (文档)
每个 document 都有一个 IntersectionObserverTaskQueued 标志,初始化为 false。
3.1.2. Element (元素)
Element 对象有一个内部 [[RegisteredIntersectionObservers]] 槽,初始化为空列表。此列表持有 IntersectionObserverRegistration 记录,这些记录具有一个持有 IntersectionObserver 的 observer 属性、一个持有 -1 到观察器 thresholds 属性长度(含)之间数字的 previousThresholdIndex 属性,以及一个持有布尔值的 previousIsIntersecting 属性。
3.1.3. IntersectionObserver (交叉观察器)
IntersectionObserver 对象拥有内部 [[QueuedEntries]] 和 [[ObservationTargets]] 槽(初始化为空列表),以及由 IntersectionObserver(callback, options) 初始化的内部 [[callback]] 槽。它们还拥有内部 [[rootMargin]] 和 [[scrollMargin]] 槽,它们是四个像素长度或百分比的列表。
3.2. Algorithms (算法)
3.2.1. Initialize a new IntersectionObserver (初始化新的交叉观察器)
若要 初始化新的 IntersectionObserver,给定一个 IntersectionObserverCallback callback 和一个 IntersectionObserverInit 字典 options,请执行以下步骤:
-
设 this 为一个新的
IntersectionObserver对象。 -
将 this 的内部
[[callback]]槽设置为 callback。 -
尝试从 options.
rootMargin解析边距。如果返回一个列表,则将 this 的内部[[rootMargin]]槽设置为该列表。否则,抛出一个SyntaxError异常。 -
尝试从 options.
scrollMargin解析边距。如果返回一个列表,则将 this 的内部[[scrollMargin]]槽设置为该列表。否则,抛出一个SyntaxError异常。 -
设 thresholds 为等于 options.
threshold的列表。 -
如果 thresholds 中的任何值小于 0.0 或大于 1.0,则抛出一个
RangeError异常。 -
将 thresholds 按升序排序。
-
如果 thresholds 为空,则将
0追加到 thresholds。 -
thresholds属性获取器将返回此已排序的 thresholds 列表。 -
返回 this。
3.2.2. Observe a target Element (观察目标元素)
若要 观察目标元素,给定一个 IntersectionObserver observer 和一个 Element target,执行以下步骤:
-
如果 target 存在于 observer 的内部
[[ObservationTargets]]槽中,则返回。 -
设 intersectionObserverRegistration 为一个
IntersectionObserverRegistration记录,其observer属性设置为 observer,previousThresholdIndex属性设置为-1,previousIsIntersecting属性设置为false。 -
将 intersectionObserverRegistration 追加到 target 的内部
[[RegisteredIntersectionObservers]]槽中。 -
将 target 添加到 observer 的内部
[[ObservationTargets]]槽中。
3.2.3. Unobserve a target Element (取消观察目标元素)
若要 取消观察目标元素,给定一个 IntersectionObserver observer 和一个 Element target,执行以下步骤:
-
从 target 内部的
[[RegisteredIntersectionObservers]]槽中移除其observer属性等于 this 的IntersectionObserverRegistration记录(如果存在)。 -
从 this 内部的
[[ObservationTargets]]槽中移除 target(如果存在)。
3.2.4. Queue an Intersection Observer Task (队列化交叉观察器任务)
IntersectionObserver 任务源 是一个任务源,用于调度任务以执行 § 3.2.5 通知交叉观察器。
若要为 document document 队列化交叉观察器任务,请执行以下步骤:
-
如果 document 的 IntersectionObserverTaskQueued 标志设置为 true,则返回。
-
将 document 的 IntersectionObserverTaskQueued 标志设置为 true。
-
在与该
document的事件循环关联的 IntersectionObserver 任务源上队列化一个任务,以通知交叉观察器。
3.2.5. Notify Intersection Observers (通知交叉观察器)
若要为 document document 通知交叉观察器,执行以下步骤:
-
将 document 的 IntersectionObserverTaskQueued 标志设置为 false。
-
设 notify list 为根 (
root) 位于 document 的 DOM 树中的所有IntersectionObserver的列表。 -
对于 notify list 中的每个
IntersectionObserver对象 observer,执行以下步骤:-
如果 observer 的内部
[[QueuedEntries]]槽为空,则继续。 -
设 queue 为 observer 的内部
[[QueuedEntries]]槽的副本。 -
清除 observer 的内部
[[QueuedEntries]]槽。 -
设 callback 为 observer 的内部
[[callback]]槽的值。 -
调用 callback,将 queue 作为第一个参数,将 observer 作为第二个参数,并将 observer 作为回调 this 值。如果抛出异常,则报告异常。
-
3.2.6. Queue an IntersectionObserverEntry (队列化 IntersectionObserverEntry)
若要为 IntersectionObserver observer 队列化 IntersectionObserverEntry,给定 document document;DOMHighResTimeStamp time;DOMRects rootBounds、boundingClientRect、intersectionRect 和 isIntersecting 标志;以及 Element target;执行以下步骤:
-
构造一个
IntersectionObserverEntry,传入 time、rootBounds、boundingClientRect、intersectionRect、isIntersecting 和 target。 -
将其追加到 observer 的内部
[[QueuedEntries]]槽中。 -
为 document 队列化一个交叉观察器任务。
3.2.7. Compute the Intersection of a Target Element and the Root (计算目标元素与根的交叉)
若要 计算 目标 target 与 交叉根 root 之间的 交叉,执行以下步骤:
-
设 intersectionRect 为获取 target 边界框的结果。
-
设 container 为 target 的包含块。
-
当 container 不是 root 时:
-
如果 container 是嵌套浏览上下文的
document,则通过裁剪到该document的视口来更新 intersectionRect,并更新 container 为该 container 的浏览上下文容器。 -
将 intersectionRect 映射到 container 的坐标空间。
-
如果 container 是滚动容器,应用
IntersectionObserver的[[scrollMargin]]到 container 的裁剪矩形,如应用滚动边距到滚动端口中所述。 -
如果 container 具有内容裁剪或 css clip-path 属性,则通过应用 container 的裁剪来更新 intersectionRect。
-
如果 container 是浏览上下文的根元素,则更新 container 为该浏览上下文的
document;否则,更新 container 为 container 的包含块。
-
-
将 intersectionRect 映射到 root 的坐标空间。
-
通过与根交叉矩形取交集来更新 intersectionRect。
-
返回 intersectionRect。
3.2.8. Run the Update Intersection Observations Steps (执行更新交叉观察步骤)
若要为 Document document 执行更新交叉观察步骤(给定时间戳 time),执行以下步骤:
-
设 observer list 为根 (
root) 位于 document 的 DOM 树中的所有IntersectionObserver的列表。对于顶级浏览上下文,这包括隐式根观察器。 -
对于 observer list 中的每个 observer:
-
设 rootBounds 为 observer 的根交叉矩形。
-
对于 observer 内部
[[ObservationTargets]]槽中的每个 target(按在每个 target 上调用observe()的顺序处理):-
令
-
设 thresholdIndex 为 0。
-
设 isIntersecting 为 false。
-
设 targetRect 为一个
DOMRectReadOnly,其 x、y、width 和 height 设置为 0。 -
设 intersectionRect 为一个
DOMRectReadOnly,其 x、y、width 和 height 设置为 0。
-
-
将 targetRect 设置为通过获取 target 边界框而获得的
DOMRectReadOnly。 -
设 targetArea 为 targetRect 的面积。
-
设 intersectionArea 为 intersectionRect 的面积。
-
如果 targetRect 和 rootBounds 相交或边缘邻接,即使交叉面积为零(因为 rootBounds 或 targetRect 面积为零),也将 isIntersecting 设置为 true。
-
如果 targetArea 不为零,则设 intersectionRatio 为 intersectionArea 除以 targetArea。
否则,如果 isIntersecting 为 true,则设 intersectionRatio 为1;如果 isIntersecting 为 false,则设为0。 -
将 thresholdIndex 设置为 observer.
thresholds中第一个其值大于 intersectionRatio 的条目的索引;如果 intersectionRatio 大于或等于 observer.thresholds中的最后一个条目,则设置为 observer.thresholds的长度。 -
设 intersectionObserverRegistration 为 target 内部
[[RegisteredIntersectionObservers]]槽中observer属性等于 observer 的IntersectionObserverRegistration记录。 -
设 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 Lifetime (IntersectionObserver 生命周期)
IntersectionObserver 将保持存活,直到满足以下两个条件:
- 没有对观察器的脚本引用。
- 观察器没有观察任何目标。
IntersectionObserver 将持续观察一个目标,直到调用了该观察者的 unobserve() 方法并传入该目标作为参数,或者调用了观察者的 disconnect() 方法。
3.4. 外部规范集成
3.4.1. HTML 处理模型:事件循环
在 HTML 事件循环处理模型的“更新渲染”步骤中,存在一个 Intersection Observer 处理步骤作为子步骤。
3.4.2. 待处理的初始 IntersectionObserver 目标
如果存在至少一个满足以下条件的IntersectionObserver,则称一个 document 拥有 待处理的初始 IntersectionObserver 目标- observer 的
root位于该 document 中(对于顶级浏览上下文,这包括隐式根观察者)。 - observer 在其
[[ObservationTargets]]插槽中至少有一个 target,且尚未为该目标排入任何IntersectionObserverEntry。
在 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 出现之前,Web 开发人员曾以非常巧妙(有时甚至是怪异)的方式使用其他 API 来窃取 IntersectionObserver 所提供的信息。从纯粹实用的角度来看,该 API 并没有揭示任何通过其他手段无法获得的信息。
另一个考量是 IntersectionObserver 使用了 DOMHighResTimeStamp,它自身也有隐私和安全方面的考量。不过,IntersectionObserver 不太可能遭受与时间相关的漏洞利用。时间戳最多在每次渲染更新时生成一次(见 § 3.4.1 HTML 处理模型:事件循环),这对于常见的定时攻击来说频率太低了。
6. 国际化
本节是非规范性的。
没有已知的国际化相关问题。
7. 致谢
特别感谢所有贡献者,正是你们的技术投入和建议促成了本规范的改进。