交叉观察者

W3C 工作草案,

关于本文档的更多信息
此版本:
https://www.w3.org/TR/2023/WD-intersection-observer-20231018/
最新发布版本:
https://www.w3.org/TR/intersection-observer/
编辑草案:
https://w3c.github.io/IntersectionObserver/
之前的版本:
历史记录:
https://www.w3.org/standards/history/intersection-observer/
测试套件:
http://w3c-test.org/intersection-observer/
反馈:
GitHub
编辑:
(Google)
(Mozilla)
(Google)
前任编辑:
(Google)

摘要

本规范描述了一个API,用于理解DOM元素(“目标”)相对于包含元素或顶级视口(“根”)的可见性和位置。位置信息是异步传递的,对于理解元素的可见性以及实现DOM内容的预加载和延迟加载非常有用。

本文档的状态

本节描述了本文档在发布时的状态。当前W3C出版物列表和本技术报告的最新修订版可以在W3C技术报告索引中找到,网址为:https://www.w3.org/TR/。

本文档由Web 应用工作组作为工作草案发布。本文件旨在成为W3C推荐标准。

本文档由Web 应用工作组根据推荐轨道发布为工作草案。 欢迎对本规范的反馈和评论。请使用GitHub问题。历史讨论可以在public-webapps@w3.org存档中找到。

作为工作草案发布不意味着W3C及其成员的认可。这是一个草案文档,可能会随时更新、替换或被其他文档取代。引用本文档为工作进展中的内容是不恰当的。

本文档由在W3C 专利政策下运作的小组制作。W3C维护所有与小组交付物相关的专利披露的公共列表;该页面还包括披露专利的说明。拥有专利实际知识的个人认为该专利包含基本要求的必须根据W3C专利政策第6节披露信息。

本文件受2023年6月12日W3C流程文件管理。

1. 介绍

Web 的传统位置计算机制依赖于对 DOM 状态的显式查询,而这些查询已知会导致(昂贵的)样式重新计算和布局,并且经常因为持续轮询这些信息而成为显著性能开销的来源。

一个依赖这些行为的常见实践体系已经发展起来,包括(但不限于):

这些用例有几个共同点:

  1. 它们可以表示为关于单个元素相对于某些其他元素(或全局视口)状态的被动“查询”。

  2. 它们不施加严格的延迟要求;也就是说,信息可以异步交付(例如,从另一个线程)而不会产生惩罚。

  3. 几乎所有现有 Web 平台功能组合对它们的支持都很差,尽管它们被广泛使用,但仍需开发者付出额外的努力。

一个显著的非目标是像素精确的关于实际显示内容的信息(在某些浏览器架构中,面对滤镜、WebGL 和其他功能时,获取这些信息可能相当困难)。在所有这些场景中,即使信息在稍微延迟的情况下交付,并且没有完美的合成结果数据,该信息仍然是有用的。

Intersection Observer API 通过为开发者提供一种新的方法来异步查询元素相对于其他元素或全局视口的位置,解决了上述问题。异步交付消除了昂贵的 DOM 和样式查询、持续轮询以及使用自定义插件的需求。通过消除这些方法的需求,它允许应用程序显著降低 CPU、GPU 和能量成本。

var observer = new IntersectionObserver(changes => {
for (const change of 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);             // 元素 target
}
}, {});

// 观察特定目标元素的交集事件。
observer.observe(target);

// 停止观察特定目标元素的交集事件。
observer.unobserve(target);

// 停止观察所有目标元素的阈值事件。
observer.disconnect();

2. Intersection Observer

Intersection Observer API 使开发者能够理解 目标 DOM 元素相对于 交叉根 的可见性和位置。

2.1. IntersectionObserverCallback

callback IntersectionObserverCallback = undefined (sequence<IntersectionObserverEntry> entries, IntersectionObserver observer);

当 目标 的与 交叉根 的交集发生变化时,将调用此回调,如 处理模型 所述。

2.2. IntersectionObserver 接口

IntersectionObserver 接口可用于观察 交叉根 和一个或多个 目标 Element 之间交集的变化。

交叉根 对于 IntersectionObserver 来说,是其 root 属性的值,如果属性为非 null;否则,它是 顶级浏览上下文 的 document 节点,称为 隐式根。

具有非 null 的 IntersectionObserver 被称为 显式根观察者,并且它可以观察任何在 包含块链 中属于 root 的后代的 目标 Element。具有 null root 的 IntersectionObserver 被称为 隐式根观察者。隐式根观察者的有效 目标 包括在 顶级浏览上下文 中的任何 Element,以及在属于 顶级浏览上下文 的 后代浏览上下文列表 的任何 嵌套浏览上下文 中的任何 Element。

当处理 隐式根观察者 时,API 对目标的 相关设置对象 的 origin 是否与顶级 origin 是 同源域 进行了区分,称为 同源域目标;而与 跨源域目标 相反。显式根观察者 的任何 目标 也是 同源域目标,因为 目标 必须与 交叉根 位于相同的 文档 中。

注意: 在 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() 所有 target 并 observe() 剩余的,或者为每个 target 创建一个单独的 IntersectionObserver。

disconnect()

对于 this 的内部 [[ObservationTargets]] 槽中的每个 target:

  1. 从 target 的内部 [[RegisteredIntersectionObservers]] 槽中移除 IntersectionObserverRegistration 记录,其 observer 属性等于 this。

  2. 从 this 的内部 [[ObservationTargets]] 槽中移除 target。

takeRecords()
  1. 让 queue 成为 this 的内部 [[QueuedEntries]] 槽的副本。

  2. 清除 this 的内部 [[QueuedEntries]] 槽。

  3. 返回 queue。

root, 类型 (Element 或 Document), 只读, 可为空

提供给 IntersectionObserver 构造函数的 root,如果没有提供则为 null。

rootMargin, 类型 DOMString, 只读

应用于 根交叉矩形 的偏移量,有效地扩展或缩小用于计算交叉的框。这些偏移量仅在处理 同源域目标 时应用;对于 跨源域目标,它们将被忽略。

获取时,返回以空格分隔的序列化 [[rootMargin]] 的结果,其中像素长度序列化为数字值加 "px",百分比序列化为数字值加 "%”。请注意,这不保证与传递给 IntersectionObserver 构造函数的 options.rootMargin 相同。如果没有传递给 IntersectionObserver 构造函数的 rootMargin,则此属性的值为 "0px 0px 0px 0px"。

scrollMargin, 类型 DOMString, 只读

偏移量应用于从 交叉根 到 目标 路径上的 滚动端口,有效地扩展或缩小用于计算交叉的裁剪矩形。

获取时,返回以空格分隔的序列化 [[scrollMargin]] 的结果,其中像素长度序列化为数字值加 "px",百分比序列化为数字值加 "%”。请注意,这不保证与传递给 IntersectionObserver 构造函数的 options.scrollMargin 相同。如果没有传递给 IntersectionObserver 构造函数的 scrollMargin,则此属性的值为 "0px 0px 0px 0px"。

thresholds, 类型 FrozenArray<double>, 只读

阈值列表,按数值升序排序,每个阈值是观察目标的交叉面积与边界框面积的比率。当任何一个目标跨越这些阈值时,将生成通知。如果没有为 IntersectionObserver 构造函数提供 options.threshold,或者序列为空,则此属性的值将为 [0]。

如果一个 Element 的计算样式具有 overflow 属性,使其内容被裁剪到元素的 填充边缘,则定义为具有 内容裁剪。

IntersectionObserver 的 根交叉矩形 是我们将用来检查目标的矩形。

如果 IntersectionObserver 是一个 隐式根观察者,
它被视为根是 顶级浏览上下文 的 document, 根据 document 的以下规则处理。
如果 交叉根 是 document,
它的大小是 document 的 视口(请注意,此处理步骤只能在 document 是 完全活跃 时才能到达)。
否则,如果 交叉根 具有 内容裁剪,
它是元素的 填充区域。
否则,
它是获取 边界框 的结果,适用于 交叉根。

当为 同源域目标 计算 根交叉矩形 时, 根据 IntersectionObserver 的 [[rootMargin]] 槽中的偏移量扩展矩形, 类似于 CSS 的 margin 属性, 四个值分别表示顶部、右侧、底部和左侧边缘的偏移量, 正长度表示向外偏移。 百分比相对于未稀释矩形的宽度进行解析。

注意: rootMargin 仅适用于 交叉根 本身。 如果一个 目标 Element 被除 交叉根 之外的祖先元素裁剪,则该裁剪不受 rootMargin 影响。

要 将滚动边距应用于滚动端口

为 滚动端口 计算交叉矩形时 为 同源域目标,根据 IntersectionObserver 的 [[scrollMargin]] 槽中的偏移量扩展矩形,类似于 CSS 的 margin 属性,四个值分别表示顶部、右侧、底部和左侧边缘的偏移量,正长度表示向外偏移。百分比相对于未稀释矩形的宽度进行解析。

这些偏移量仅在处理 同源域目标 时应用;对于 跨源域目标,它们将被忽略。

注意: scrollMargin 影响 目标 的所有可滚动祖先的裁剪,直到并包括 交叉根。scrollMargin 和 rootMargin 都应用于可滚动的 交叉根 矩形。

注意: 根交叉矩形 和 滚动端口 交叉矩形不受 捏合缩放 的影响,并将报告未调整的 视口,这与捏合缩放的意图(像放大镜一样操作而不是改变布局)一致。

要解析边距(根或滚动) 从输入字符串 marginString, 返回一个包含 4 个像素长度或百分比的列表, 或者失败:

  1. 解析组件值列表 marginString,将结果存储为 tokens。

  2. 从 tokens 中删除所有空白符。

  3. 如果 tokens 的长度大于 4,返回失败。

  4. 如果 tokens 中没有元素,将 tokens 设置为 ["0px"]。

  5. 替换 tokens 中的每个 token:

    • 如果 token 是一个 绝对长度 尺寸 令牌,将其替换为等效的像素长度。

    • 如果 token 是一个 <percentage> 令牌,将其替换为等效的百分比。

    • 否则,返回失败。

  6. 如果 tokens 中有一个元素,向 tokens 添加三个该元素的副本。否则,如果 tokens 中有两个元素,分别添加每个元素的副本。否则,如果 tokens 中有三个元素,向 tokens 添加第二个元素的副本。

  7. 返回 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,只读

通过获取边界框为target获得的DOMRectReadOnly。

intersectionRect, 类型为 DOMRectReadOnly,只读

boundingClientRect 被 target 的各个祖先元素的剪辑矩形(不包括 root)相交,且与 根交集矩形 相交。 该值表示在 根交集矩形 内实际可见的 target 部分。

isIntersecting, 类型为 boolean,只读

当 target 与 root 相交时返回 true,否则返回 false。 该标志使得可以区分 IntersectionObserverEntry 发出从相交到不相交的过渡信号; 以及发出从不相交到相交但交集矩形面积为零(当边缘相邻或 boundingClientRect 面积为零时)的过渡信号的 IntersectionObserverEntry。

intersectionRatio, 类型为 double,只读

如果 boundingClientRect 的面积不为零, 该值将是 intersectionRect 面积与 boundingClientRect 面积的比率。 否则,如果 isIntersecting 为 true,则该值为 1, 如果为 false,则该值为 0。

rootBounds, 类型为 DOMRectReadOnly,只读,nullable

对于 同源域目标,该值将是 根交集矩形。 否则,该值为 null。 注意,如果目标与 浏览上下文 中的 交集根 在不同的坐标系统中, 该值将与 boundingClientRect 和 intersectionRect 处于不同的坐标系统中。

target, 类型为 Element,只读

与 交集根 的交集发生变化的 元素。

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 或 Document),可为空,默认为 null

用于交集检测的 根。 如果未提供,则使用 隐式根。

rootMargin, 类型为 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 或 sequence<double>),默认值为 0

触发回调的阈值列表。当 intersectionRect 的面积从大于或等于任何阈值变为小于该阈值时,或者反之,都会调用回调。

阈值必须在 [0, 1.0] 范围内,并代表通过获取边界框为target生成的矩形区域的百分比。

注意: 0.0 实际上表示“任何非零像素数”。

3. 处理模型

本节概述了用户代理在实现Intersection Observer API 时必须采取的步骤。

3.1. 内部槽定义

3.1.1. 文档

每个document都有一个IntersectionObserverTaskQueued标志,初始值为false。

3.1.2. 元素

Element对象具有内部[[RegisteredIntersectionObservers]]槽,初始化为空列表。 此列表包含IntersectionObserverRegistration记录, 这些记录具有一个observer属性,持有一个IntersectionObserver对象, 一个previousThresholdIndex属性, 其值在-1到观察者的thresholds属性的长度之间(包括),以及一个previousIsIntersecting属性,持有一个布尔值。

3.1.3. IntersectionObserver

IntersectionObserver对象具有内部[[QueuedEntries]]和[[ObservationTargets]]槽,这些槽初始化为空列表,还有一个内部[[callback]]槽 由IntersectionObserver(callback, options)初始化。 它们还具有内部[[rootMargin]]和[[scrollMargin]]槽,它们是由四个像素长度或百分比组成的列表。

3.2. 算法

3.2.1. 初始化一个新的IntersectionObserver

要初始化一个新的IntersectionObserver,给定一个IntersectionObserverCallback callback和一个IntersectionObserverInit 字典options,执行以下步骤:

  1. 令this为一个新的IntersectionObserver对象

  2. 将this的内部[[callback]]槽设置为callback。

  3. 尝试从options.rootMargin解析出一个margin。 如果返回了一个列表,将this的内部[[rootMargin]]槽设置为该列表。 否则,抛出一个SyntaxError异常。

  4. 尝试从options.scrollMargin解析出一个margin。 如果返回了一个列表,将this的内部[[scrollMargin]]槽设置为该列表。 否则,抛出一个SyntaxError异常。

  5. 令thresholds为与options.threshold等价的一个列表。

  6. 如果thresholds中的任何值小于0.0或大于1.0,抛出一个RangeError异常。

  7. 将thresholds按升序排序。

  8. 如果thresholds为空,则向thresholds中追加0。

  9. thresholds属性的getter将返回这个排序后的thresholds列表。

  10. 返回this。

3.2.2. 观察一个目标元素

要观察一个目标元素,给定一个IntersectionObserver observer和一个Element target,遵循以下步骤:

  1. 如果target在observer的内部[[ObservationTargets]]槽中, 则返回。

  2. 令intersectionObserverRegistration为一个IntersectionObserverRegistration记录, 该记录具有observer属性,设置为observer, previousThresholdIndex属性,设置为-1, 和previousIsIntersecting属性,设置为false。

  3. 将intersectionObserverRegistration附加到target的内部[[RegisteredIntersectionObservers]]槽中。

  4. 将target添加到observer的内部[[ObservationTargets]]槽中。

3.2.3. 停止观察一个目标元素

要停止观察一个目标元素,给定一个IntersectionObserver observer和一个Element target,请执行以下步骤:

  1. 从target的内部[[RegisteredIntersectionObservers]] 插槽中移除IntersectionObserverRegistration 记录,其observer 属性等于this(如果存在)。

  2. 从this的内部[[ObservationTargets]] 插槽中移除target(如果存在)。

3.2.4. 排队一个 Intersection Observer 任务

IntersectionObserver 任务源是一个用于调度任务的任务源,用于§ 3.2.5 通知 Intersection Observers。

要为document document排队一个Intersection Observer 任务,请执行以下步骤:

  1. 如果document的IntersectionObserverTaskQueued标志被设置为 true, 则返回。

  2. 将document的IntersectionObserverTaskQueued标志设置为 true。

  3. 排队一个任务到与document的事件循环关联的IntersectionObserver 任务源,以通知 Intersection Observers。

3.2.5. 通知 Intersection Observers

要通知 Intersection Observers为一个document document,请执行以下步骤:

  1. 将document的IntersectionObserverTaskQueued标志设置为 false。

  2. 让notify list成为所有IntersectionObserver 的列表,其root 位于document的 DOM 树中。

  3. 对于notify list中的每个IntersectionObserver 对象observer,执行以下步骤:

    1. 如果observer的内部[[QueuedEntries]] 插槽为空, 继续。

    2. 让queue成为observer的内部[[QueuedEntries]] 插槽的副本。

    3. 清空observer的内部[[QueuedEntries]] 插槽。

    4. 让callback成为observer的内部[[callback]] 插槽的值。

    5. 使用queue作为第一个参数,observer作为第二个参数, 并将observer作为回调的 this 值调用callback。 如果这引发了异常,请报告该异常。

3.2.6. 排队一个 IntersectionObserverEntry

要为一个IntersectionObserver observer排队一个IntersectionObserverEntry,给定一个document document;DOMHighResTimeStamp time;DOMRect们 rootBounds,boundingClientRect,intersectionRect,和 isIntersecting标志; 和一个Element target, 请执行以下步骤:

  1. 构造一个IntersectionObserverEntry, 传入time,rootBounds,boundingClientRect, intersectionRect,isIntersecting,和target。

  2. 将其附加到observer的内部[[QueuedEntries]] 插槽中。

  3. 为document排队一个 Intersection Observer 任务。

3.2.7. 计算目标元素和根的相交部分

要计算目标target和相交根root之间的相交部分,请运行以下步骤:

  1. 让intersectionRect成为获取target的边界框的结果。

  2. 让container成为target的包含块。

  3. 当container不是root时:

    1. 如果container是嵌套浏览上下文的文档, 通过将其剪裁到该文档的视口来更新intersectionRect,并更新container 为container的浏览上下文容器。

    2. 将intersectionRect映射到container的坐标空间。

    3. 如果 container 是一个 滚动容器,应用 IntersectionObserver 的 [[scrollMargin]] 到 container 的剪裁矩形,如 应用滚动边距到滚动端口 中所述。

    4. 如果container有一个内容剪裁或一个 css 剪裁路径属性, 通过应用container的剪裁来更新intersectionRect。

    5. 如果container是浏览上下文的根元素, 更新container为该浏览上下文的文档; 否则,更新container为container的包含块。

  4. 将intersectionRect映射到root的坐标空间。

  5. 通过与根相交矩形相交来更新intersectionRect。

  6. 将intersectionRect映射到包含target的文档的视口的坐标空间。

  7. 返回intersectionRect。

3.2.8. 运行更新相交观察步骤

要为文档document运行 更新相交观察步骤,给定一个时间戳time,请运行以下步骤:

  1. 让observer list成为所有IntersectionObserver的列表, 其root在document的DOM树中。 对于顶级浏览上下文,这包括隐式根观察者。

  2. 对于observer list中的每个observer:

    1. 让rootBounds成为observer的根相交矩形。

    2. 对于observer的内部[[ObservationTargets]] 插槽中的每个target,按照observe()调用的顺序处理每个target:

      1. 让:

        • thresholdIndex为0。

        • isIntersecting为false。

        • targetRect为一个DOMRectReadOnly,其x、 y、width和height设置为0。

        • intersectionRect为一个DOMRectReadOnly,其x、 y、width和height设置为0。

      2. 如果相交根不是隐式根,且target不在与document 相同的文档中,请跳至步骤11。

      3. 如果相交根是Element,且target不是相交根的后代,target不在包含块链中,请跳至步骤11。

      4. 将targetRect设置为通过获取target的边界框获得的DOMRectReadOnly。

      5. 让intersectionRect成为在target和observer的相交根上运行计算相交算法的结果。

      6. 让targetArea为targetRect的面积。

      7. 让intersectionArea为intersectionRect的面积。

      8. 如果targetRect和rootBounds相交或边缘相邻,即使相交面积为零(因为rootBounds或targetRect的面积为零),让isIntersecting为true。

      9. 如果targetArea非零,让intersectionRatio为intersectionArea除以targetArea。 否则,如果isIntersecting为true,让intersectionRatio为1,如果isIntersecting为false,让intersectionRatio为0。

      10. 将thresholdIndex设置为observer.thresholds 中第一个值大于intersectionRatio的索引,或者如果intersectionRatio大于或等于observer.thresholds中的最后一个条目,则为observer.thresholds的长度。

      11. 让intersectionObserverRegistration成为target的内部[[RegisteredIntersectionObservers]] 插槽中observer的observer属性相等的IntersectionObserverRegistration记录。

      12. 让previousThresholdIndex为intersectionObserverRegistration的previousThresholdIndex属性。

      13. 让previousIsIntersecting为intersectionObserverRegistration的previousIsIntersecting属性。

      14. 如果thresholdIndex不等于previousThresholdIndex,或isIntersecting不等于previousIsIntersecting,队列一个IntersectionObserverEntry,传入observer、time、rootBounds、targetRect、intersectionRect、isIntersecting和target。

      15. 将thresholdIndex赋值给intersectionObserverRegistration的previousThresholdIndex属性。

      16. 将isIntersecting赋值给intersectionObserverRegistration的previousIsIntersecting属性。

3.3. IntersectionObserver 生命周期

一个IntersectionObserver 将保持活动状态,直到以下两个条件都成立:

一个IntersectionObserver 将继续观察目标,直到调用观察者的unobserve() 方法并以目标作为参数;或调用观察者的disconnect()。

3.4. 外部规范集成

3.4.1. HTML 处理模型:事件循环

一个 Intersection Observer 处理步骤作为子步骤存在于 "更新渲染" 步骤中, 在HTML 事件循环处理模型中。

3.4.2. 等待初始 IntersectionObserver 目标

一个document 被认为有等待初始 IntersectionObserver 目标,如果 至少有一个IntersectionObserver 满足以下条件:

  1. observer的root 在document中(对于顶级浏览上下文,这包括隐式根观察者)。
  2. observer在其[[ObservationTargets]] 插槽中有至少一个target,该target尚未排队任何IntersectionObserverEntry。

在HTML 事件循环处理模型中,在"更新渲染"步骤下,"不必要的渲染"步骤应修改为添加一个额外的 跳过渲染更新的要求:

4. 无障碍性考虑

本节为非规范性内容。

对于核心的 IntersectionObserver 规范(本文档),目前没有已知的无障碍性考虑。 然而,有一些相关的规范和提案利用并参考了本规范,这些规范可能有其自身的无障碍性考虑。特别是,HTML § 2.5.7 延迟加载属性和CSS 包含 2 § 4 完全隐藏元素内容:content-visibility 属性的规范可能会对HTML § 6.9 页面查找、HTML § 6.6.3 tabindex 属性和空间导航产生影响。

5. 隐私和安全

本节为非规范性内容。

与此 API 相关的主要隐私问题与它可能提供给在跨源 iframe 上下文中运行的代码的信息有关(即跨源域目标的情况)。尤其是:

值得注意的是,在IntersectionObserver 之前,网页开发者曾以非常巧妙(且恐怖)的方式使用其他 API 来获取IntersectionObserver 提供的信息。从实际操作的角度来看,该 API 并未揭示通过其他方式无法获得的任何信息。

另一个考虑因素是IntersectionObserver 使用DOMHighResTimeStamp, 该属性本身具有隐私和安全方面的考虑。然而,IntersectionObserver 受时间相关攻击的可能性不大。时间戳最多每次渲染更新生成一次(见§ 3.4.1 HTML 处理模型:事件循环), 这对于通常的时间攻击来说太不频繁。

6. 国际化

本节为非规范性内容。

目前没有已知的国际化问题。

7. 致谢

特别感谢所有贡献者的技术投入和建议,这些建议促进了本规范的改进。

一致性

文档惯例

一致性要求通过描述性断言和 RFC 2119 术语的结合来表达。 在本文档的规范性部分中,关键字“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“MAY”和“OPTIONAL” 应按照 RFC 2119 的描述进行解释。然而,为了提高可读性,这些词在本规范中并未全部以大写字母出现。

除明确标记为非规范性部分、示例和注释的章节外,本规范的所有文本均为规范性内容。[RFC2119]

本规范中的示例以“例如”一词引入,或通过class="example"与规范性文本分开,例如:

这是一个说明性示例的示例。

说明性注释以“注”一词开头,并通过class="note"与规范性文本分开,例如:

注,这是一个说明性注释。

一致性算法

在算法中以命令式措辞表达的要求(例如“删除任何前导空格字符”或“返回 false 并中止这些步骤”)应根据引入算法时使用的关键字(“必须”、“应该”、“可以”等)的含义来解释。

以算法或具体步骤表达的一致性要求可以以任何方式实现,只要最终结果是等效的即可。特别是,本规范中定义的算法旨在易于理解,并非旨在具有高性能。我们鼓励实现者进行优化。

索引

本规范定义的术语

引用定义的术语

参考文献

规范性引用

[CSS-BOX-4]
Elika Etemad. CSS 盒模型模块 第4级. 2022年11月3日. WD. URL: https://www.w3.org/TR/css-box-4/
[CSS-CONTAIN-2]
Tab Atkins Jr.; Florian Rivoal; Vladimir Levin. CSS 包含模块 第2级. 2022年9月17日. WD. URL: https://www.w3.org/TR/css-contain-2/
[CSS-OVERFLOW-3]
Elika Etemad; Florian Rivoal. CSS 溢出模块 第3级. 2023年3月29日. WD. URL: https://www.w3.org/TR/css-overflow-3/
[CSS-SYNTAX-3]
Tab Atkins Jr.; Simon Sapin. CSS 语法模块 第3级. 2021年12月24日. CR. URL: https://www.w3.org/TR/css-syntax-3/
[CSS-VALUES-3]
Tab Atkins Jr.; Elika Etemad. CSS 值与单位模块 第3级. 2022年12月1日. CR. URL: https://www.w3.org/TR/css-values-3/
[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS 值与单位模块 第4级. 2023年4月6日. WD. URL: https://www.w3.org/TR/css-values-4/
[CSSOM-VIEW-1]
Simon Pieters. CSSOM 视图模块. 2016年3月17日. WD. URL: https://www.w3.org/TR/cssom-view-1/
[DOM]
Anne van Kesteren. DOM 标准. 现行标准. URL: https://dom.spec.whatwg.org/
[GEOMETRY-1]
Simon Pieters; Chris Harrelson. 几何接口模块 第1级. 2018年12月4日. CR. URL: https://www.w3.org/TR/geometry-1/
[HTML]
Anne van Kesteren; et al. HTML 标准. 现行标准. URL: https://html.spec.whatwg.org/multipage/
[RFC2119]
S. Bradner. RFC 中使用的关键字,以指示要求级别. 1997年3月. 最佳现行实践. URL: https://datatracker.ietf.org/doc/html/rfc2119
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 标准. 现行标准. URL: https://webidl.spec.whatwg.org/

IDL 索引

callback IntersectionObserverCallback = undefined (sequence<IntersectionObserverEntry> entries, IntersectionObserver observer);

[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();
};

[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;
};

dictionary IntersectionObserverInit {
  (Element or Document)?  root = null;
  DOMString rootMargin = "0px";
  DOMString scrollMargin = "0px";
  (double or sequence<double>) threshold = 0;
};

✔MDN

IntersectionObserver/IntersectionObserver

In all current engines.

Firefox55+Safari12.1+Chrome51+
Opera?Edge79+
Edge (Legacy)15+IENone
Firefox for Android55+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IntersectionObserver/disconnect

In all current engines.

Firefox55+Safari12.1+Chrome51+
Opera?Edge79+
Edge (Legacy)15+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IntersectionObserver/observe

In all current engines.

Firefox55+Safari12.1+Chrome51+
Opera?Edge79+
Edge (Legacy)15+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IntersectionObserver/root

In all current engines.

Firefox55+Safari12.1+Chrome51+
Opera?Edge79+
Edge (Legacy)15+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IntersectionObserver/rootMargin

In all current engines.

Firefox55+Safari12.1+Chrome51+
Opera?Edge79+
Edge (Legacy)15+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IntersectionObserver/takeRecords

In all current engines.

Firefox55+Safari12.1+Chrome51+
Opera?Edge79+
Edge (Legacy)15+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IntersectionObserver/thresholds

In all current engines.

Firefox55+Safari12.1+Chrome52+
Opera?Edge79+
Edge (Legacy)15+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IntersectionObserver/unobserve

In all current engines.

Firefox55+Safari12.1+Chrome51+
Opera?Edge79+
Edge (Legacy)15+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IntersectionObserver

In all current engines.

Firefox55+Safari12.1+Chrome51+
Opera?Edge79+
Edge (Legacy)15+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IntersectionObserverEntry/boundingClientRect

In all current engines.

Firefox55+Safari12.1+Chrome51+
Opera?Edge79+
Edge (Legacy)15+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IntersectionObserverEntry/intersectionRatio

In all current engines.

Firefox55+Safari12.1+Chrome51+
Opera?Edge79+
Edge (Legacy)15+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IntersectionObserverEntry/intersectionRect

In all current engines.

Firefox55+Safari12.1+Chrome51+
Opera?Edge79+
Edge (Legacy)15+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IntersectionObserverEntry/isIntersecting

In all current engines.

Firefox55+Safari12.1+Chrome58+
Opera?Edge79+
Edge (Legacy)16+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IntersectionObserverEntry/rootBounds

In all current engines.

Firefox55+Safari12.1+Chrome51+
Opera?Edge79+
Edge (Legacy)15+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IntersectionObserverEntry/target

In all current engines.

Firefox55+Safari12.1+Chrome51+
Opera?Edge79+
Edge (Legacy)15+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IntersectionObserverEntry/time

In all current engines.

Firefox55+Safari12.1+Chrome51+
Opera?Edge79+
Edge (Legacy)15+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IntersectionObserverEntry

In all current engines.

Firefox55+Safari12.1+Chrome51+
Opera?Edge79+
Edge (Legacy)15+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?