WebXR DOM 覆盖层模块

W3C 工作草案,

关于此文档的更多详细信息
此版本:
https://www.w3.org/TR/2024/WD-webxr-dom-overlays-1-20240924/
最新发布版本:
https://www.w3.org/TR/webxr-dom-overlays-1/
编辑草案:
https://immersive-web.github.io/dom-overlays/
先前版本:
历史:
https://www.w3.org/standards/history/webxr-dom-overlays-1/
反馈:
GitHub
编辑:
(Google)
前编辑:
(Google)
参与:
提交议题 (开放议题)
邮件列表归档
W3C 的 #immersive-web IRC
不稳定的 API

此文档中所表示的 API 正在开发中,可能随时更改。

有关此 API 使用的更多上下文,请参考 WebXR DOM 覆盖层 模块解释文档


摘要

WebXR DOM 覆盖层模块使用一种 在沉浸式 WebXR 会话期间显示交互式 2D Web 内容的机制,扩展了 WebXR 设备 API。启用该特性时, 用户代理会将单个 DOM 元素的内容显示为一个透明背景的 2D 矩形。

本文档状态

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

沉浸式 Web 工作组维护着一份 该组尚未处理的所有错误 报告列表。此草案突出了部分待处理议题,这些议题 仍需在工作组中讨论。对于这些议题的结果,包括其是否有效, 尚未作出决定。 强烈鼓励为未解决议题提交带有拟议规范文本的拉取请求。

本文档由沉浸式 Web 工作组作为工作草案发布,并使用 推荐标准 轨道。本文档预期成为 W3C 推荐标准。

作为工作草案发布并不意味着获得 W3C 及其成员的认可。本文档是草案文档,可能 随时被其他文档更新、替换或废弃。除作为进行中的工作外,不应引用本文档。

本文档由一个依据 W3C 专利政策运作的组制作。 W3C 维护着一份与该组交付物相关的任何 专利 披露的公开列表;该页面还包括 披露专利的说明。实际知晓某项专利,且 认为该专利包含必要 权利要求的个人,必须根据 W3C 专利政策第 6 节披露该信息。

本文档受 2023 年 11 月 03 日 W3C 流程文档约束。

1. 简介

此模块描述了一种在沉浸式 WebXR 会话期间显示交互式 2D Web 内容的机制。启用该特性时,用户代理会将单个 DOM 元素的内容显示为 一个透明背景的 2D 矩形。

1.1. 概述

当 DOM 覆盖层处于活动状态时,UA 使用 适合平台的机制,启用用户与 DOM 覆盖层内容的交互。例如,在使用 XR 控制器时,主操作会在 控制器的指向射线与 DOM 覆盖层相交的位置派发 DOM 指针事件和 click 事件。

新的 beforexrselect 事件 提供了一种方式,用于针对 DOM 覆盖层的特定区域抑制 XR 输入事件,并帮助 应用区分 DOM UI 交互和 XR 世界交互。

2. HTML API 集成

此模块向 GlobalEventHandlers 的定义添加一个新的事件类型。

2.1. onbeforexrselect

如果在输入设备的主操作 被触发时,输入源的 targetRaySpace 的 -Z 轴 与 DOM 覆盖层元素相交,则在生成 WebXR selectstart 输入事件之前,会在 DOM 覆盖层元素上派发一个类型为 beforexrselectXRSessionEvent

partial interface mixin GlobalEventHandlers {
  attribute EventHandler onbeforexrselect;
};

此事件是一个类型为 beforexrselectXRSessionEvent, 它会冒泡、可取消且是组合的。其 target 元素是被 targetRaySpace 相交的最顶层事件目标,且要么是 DOM 覆盖层元素的后代,要么是 DOM 覆盖层元素本身。

通过调用 preventDefault() 取消此事件,会抑制输入源通常会为此主操作生成的默认 WebXR 输入事件。对于此 交互序列,不会触发 selectstartselectendselect 事件。

注: 未来的 WebXR 模块可以定义会受 取消此事件影响的其他事件或 WebXR 输入相关数据,例如抑制来自瞬态输入源命中测试订阅的结果。

此事件以及事件处理器所采取的操作不会影响 DOM 事件处理,并且不会 与 DOM 事件派发同步。用户的操作会单独生成适当的 DOM 事件,例如 `"pointerdown"`,并且这些 DOM 事件可能发生在对应的 beforexrselect 事件之前或之后。这 与 beforexrselect 事件是否被取消无关,并且独立于 XR 输入事件处理器中采取的任何后续操作。

注: 此事件为应用提供了一种方式, 使其可在用户与 DOM UI 交互时抑制重复的 XR 输入事件。由于这是一个冒泡 事件,应用可以在适当的容器元素上注册处理器,从而有效地将 DOM 覆盖层的区域 标记为阻止 XR 输入。这与 DOM 元素的视觉不透明度无关。可以 显示非交互式的不透明或半透明 DOM 内容,例如不阻止 XR 输入事件的文本说明。

以下代码在 DOM 覆盖层的 交互式部分上安装一个事件处理器,以便选择性地抑制该区域的 XR 事件,同时继续为 DOM 覆盖层中被视为在交互用途上透明的其他部分生成 XR 事件。
document.getElementById('button-container').addEventListener(
  'beforexrselect', ev => ev.preventDefault());

2.2. CSS 伪类

在使用 DOM 覆盖层的沉浸式会话期间,:xr-overlay 伪类必须 匹配覆盖层元素

覆盖层元素是一个背景根

注: DOM 覆盖层元素 或其后代上的背景滤镜效果不会修改 AR 摄像头图像(如果适用),也不会修改 绘制到沉浸式会话的 XRWebGLLayer 的渲染内容。

覆盖层元素祖先的堆叠上下文(如果有)不会绘制到沉浸式会话的 显示上。

注: 由于 `position: fixed` 样式,覆盖层元素本身是一个堆叠 上下文

注: 在多显示器系统上,UA 可以在单独的显示器(例如 桌面显示器)上绘制并呈现覆盖层元素的祖先或兄弟树的堆叠上下文。

2.3. 用户代理级样式表默认值

覆盖层元素的用户代理样式表默认值如下:

:xr-overlay {
    /* 强制透明背景 */
    background: rgba(0,0,0,0) !important;

    /* 作为后代的包含块 */
    contain: paint !important;

    /* 以下样式与 :fullscreen 相同 */
    position: fixed !important;
    top: 0 !important;
    right: 0 !important;
    bottom: 0 !important;
    left: 0 !important;
    margin: 0 !important;
    box-sizing: border-box !important;
    min-width: 0 !important;
    max-width: none !important;
    min-height: 0 !important;
    max-height: none !important;
    width: 100% !important;
    height: 100% !important;
    transform: none !important;

    /* 有意不加 !important */
    object-fit: contain;
}

注: 这是基于 Fullscreen API § 5.2 用户代理级样式表默认值,并带有使 覆盖层元素背景透明的额外样式。:xr-overlay 的样式并不显式依赖 Fullscreen API 的伪类或样式,以便用户代理具有 独立于 Fullscreen API 实现它的灵活性。

注: Fullscreen API 目前没有指定 `contain: paint` 规则,尽管这与典型的 UA 行为相匹配,并计划在该规范的未来 修订版中加入。

注: 鼓励应用使用 :xr-overlay 伪类,在 会话期间有条件地设置 UI 元素样式,包括控制界面元素的可见性。

2.4. Fullscreen API 集成

UA 可以将 DOM 覆盖层作为 [FULLSCREEN] API 的一种特殊情况来实现。在这种情况下,UA 必须阻止对活动全屏元素的更改,并在沉浸式会话期间拒绝 requestFullscreen 请求。

注: DOM 覆盖层 API 要求在会话开始时指定 覆盖层元素,并且不提供在会话期间更改活动覆盖层元素的机制。 如果应用能够使用 Fullscreen API 间接更改活动覆盖层元素,则它们在各个平台上的行为会不一致。

当通过 Fullscreen API 实现 DOM 覆盖层时,root 元素堆叠上下文不会绘制到沉浸式显示上。只有顶层中的元素的堆叠 上下文,包括覆盖层元素,会绘制到沉浸式显示上。

注: 默认情况下,全屏模式使用不透明的黑色 背景。修改后的绘制规则确保不需要绘制此背景,并且 覆盖层元素的祖先或兄弟树不会通过透明的覆盖层元素可见。

注: 允许基于 Fullscreen API 的实现,主要意在用于单显示器系统,在这种系统中,页面的其余部分在 沉浸式会话期间不可见。多显示器系统在技术上可以为覆盖层元素使用 Fullscreen API ,同时在单独的显示器(例如桌面显示器)上显示页面其余部分;在这种情况下,UA 可以在该单独显示器上绘制并呈现覆盖层元素的祖先或兄弟树的堆叠上下文。

或者,UA 可以独立于 [FULLSCREEN] API 实现 DOM 覆盖层。在这种情况下,覆盖层元素仍然必须 匹配 :xr-overlay 伪类,并且必须在沉浸式视图中使用 § 2.3 用户代理级样式表默认值来为此伪类设置样式。UA 可以单独支持对覆盖层元素之外的元素使用 fullscreen API,但这不得对 DOM 覆盖层内容的显示方式产生任何影响。

注: 独立处理 DOM 覆盖层和 Fullscreen API 意在支持多显示器系统,例如连接了 VR 头显的桌面 PC。在这种情况下,Fullscreen API 可用于控制 2D 显示器上的页面内容,例如 显示带有第三人称渲染视图的全屏 canvas 元素,而 DOM 覆盖层元素 和沉浸式内容则单独显示在头显中。

在沉浸式会话使用与最初显示的网页不同的单独输出设备的多显示器系统上,覆盖层元素在沉浸式视图中显示时,作为 2D 网页的一部分 不得在其他显示器上可见或可交互。UA 可以选择在会话期间隐藏或禁用 其他显示器上的整个页面。

注: 可以将 DOM 覆盖层内容作为非交互式头显 镜像视图或类似的非网页 UI 的一部分来显示。此多显示器 限制的意图是避免在覆盖层元素同时显示在两个位置时出现不一致显示和潜在的混淆交互。 这也避免了与同时在两个单独显示器上显示 DOM 元素相关的实现挑战。

3. WebXR 设备 API 集成

此模块扩展了 XRSessionInitXRSession 的定义, 并修改了 XRInputSource 事件的行为。

3.1. XRSessionInit

此模块引入字符串 dom-overlay,作为新的有效 特性描述符,用于沉浸式会话requiredFeaturesoptionalFeatures 序列。

如果某设备能提供一种方式,使用户在沉浸式会话期间查看 DOM 内容并与之交互, 则该设备能够支持 DOM 覆盖层特性。

注: 实现选择包括手持 AR 设备上的全屏 覆盖层,或 VR 或 AR 头显中的空间浮动矩形。

DOM 内容必须像是最顶层的内容层一样进行合成。它不得被来自 XRWebGLLayer 的内容遮挡,也不得被 AR 设备的透视摄像头图像遮挡。应用可以使用普通 CSS 规则来控制 DOM 覆盖层自身内部内容的透明度和 2D 位置。

DOM 覆盖层必须从会话开始起自动对用户可见,而不需要 用户按下按钮或采取其他手动操作来使其可见。

注: 如果内容元素只是间接可见, 例如用户需要摘下头显或手动启用透视摄像头,才能查看在会话期间通常不可见的单独 2D 显示器上的内容,则设备不应声称支持 DOM 覆盖层。但是,用户携带 显示 DOM 覆盖层内容的物理触摸屏设备的沉浸式 CAVE 系统将是一种有效实现。

通过添加新的 domOverlay 成员来扩展 XRSessionInit 字典。这是 XRSessionInit 的可选成员, 但在使用 DOM 覆盖层特性时必须指定它,因为没有默认的覆盖层元素。

partial dictionary XRSessionInit {
  XRDOMOverlayInit? domOverlay;
};

如果 DOM 覆盖层特性是必需特性,但应用没有提供 domOverlay 成员,则 UA 必须将其视为未解决的必需特性,并用 NotSupportedError 拒绝 requestSession() promise。 如果它是作为可选特性请求的,则 UA 必须忽略该特性请求并且不启用 DOM 覆盖层。

注: UA 可以发出本地警告,例如开发者 控制台消息,说明 DOM 覆盖层未启用的原因。

3.2. XRSession

此模块扩展 XRSession 接口,添加一个新的只读属性,该属性反映 DOM 覆盖层特性的当前状态。

partial interface XRSession {
  readonly attribute XRDOMOverlayState? domOverlayState;
};

如果 dom-overlay 特性不受支持或未启用,则 domOverlayState 属性必须为 null。

如果该特性已启用,则属性值必须存在。

注: 应用可以检查 domOverlayState 的存在性,以验证 DOM 覆盖层特性已启用且正在工作,例如在它作为 可选特性被请求时。

注: DOM 覆盖层可能会暂时对 用户不可见,例如,如果用户代理将其放置在固定方向或位置,而在用户移动后它可能最终 位于用户视野之外。发生这种情况时,domOverlayState 属性仍保持设置。

当会话处于活动状态且有可见的 DOM 覆盖层时,UA 必须将其视为渲染机会,并以适合为 DOM 内容制作动画的速率执行 Window requestAnimationFrame() 回调。这些回调可以在不同于用于绘制 XRWebGLLayer 内容的 requestAnimationFrame() 回调的时间和频率运行。

3.3. XRInputSource

XRInputSource 开始与其主操作相对应的平台特定操作时,UA 必须在开始输入处理之前运行以下步骤,以决定是否将其视为主操作

  1. 如果在输入设备的主 操作被触发时,输入源的 targetRaySpace 与 DOM 覆盖层相交:

    1. 排队一个任务,以便在 DOM 覆盖层 root 内被 targetRaySpace 相交的最顶层事件目标上,使用 XRSessionEvent 触发一个事件,该事件名为 beforexrselect, 并将 target 设置为该元素。此事件会冒泡、可取消且是组合的。

    2. 按如下方式检查应如何处理 XR 输入:

      如果事件已取消
      1. 如果输入源是瞬态输入 源,则将其视为辅助 操作。否则,为生成 XR 输入事件的目的,忽略此操作。

      否则
      像通常针对该输入源那样,将该操作视为主操作

注: 实际上,取消 beforexrselect 事件会 抑制 XR 输入 select 事件;不会为此操作生成 selectstartselectendselect。对于瞬态 输入源,仍会生成 inputsourceschange 事件,但取消 beforexrselect 事件会导致该操作被视为辅助操作,类似于次要手指输入。

4. 初始化

应用必须通过 domOverlay 字典为 DOM 覆盖层提供配置。

dictionary XRDOMOverlayInit {
  required Element root;
};

root 属性指定将作为 DOM 覆盖层内容显示给 用户的覆盖层元素。这是必需属性,没有默认值。

以下代码将 DOM 覆盖层作为可选 特性请求。
let uiElement = document.getElementById('ui');
navigator.xr.requestSession('immersive-ar', {
    optionalFeatures: ['dom-overlay'],
    domOverlay: { root: uiElement } }).then((session) => {
    // 如果支持,则 session.domOverlayState.type 现在已设置,
    // 如果不支持该特性,则为 null。
  }
}

处于活动状态时,DOM 覆盖层元素会自动调整大小,以填满 UA 提供的 DOM 覆盖层矩形的尺寸。在会话期间,其背景颜色会自动设置为透明。

注: UA 可以使用 Fullscreen API § 5.2 用户代理级样式表默认值来设置 DOM 覆盖层元素样式,并带有一个 包含 background-color: rgba(0,0,0,0) !important; 的 额外规则,以将背景设置为透明。

一旦会话处于活动状态,domOverlayState 属性会提供有关 DOM 覆盖层的信息。

enum XRDOMOverlayType {
  "screen",
  "floating",
  "head-locked"
};

dictionary XRDOMOverlayState {
  XRDOMOverlayType type; 
};

用户代理必须将 type 设置为指示 DOM 覆盖层正在如何显示。该值在会话期间必须保持不变。

注: 从用户的角度来看,"floating" 覆盖层在按锚定到真实世界位置的方式渲染时,会被感知为静止的,并且这种样式是 VR 中交互式显示表面的常见选择。"head-locked" 覆盖层会随头部 旋转一起移动,并且没有固定的真实世界位置。

注: 此规范的未来版本可能会向覆盖层状态添加其他 属性,例如浮动覆盖层在世界空间中的当前位置。

5. 跨源内容的事件处理

对于与跨源内容(例如嵌套在 DOM 覆盖层元素内的 HTMLIFrameElement) 的用户交互,用户代理不得提供姿态或游戏手柄输入状态。

用户代理可以通过阻止用户与 跨源内容交互来满足此要求,例如通过阻止通常会被 该内容接收的 DOM 事件,或根本不加载和显示跨源内容。

如果用户代理支持与 DOM 覆盖层中的跨源内容交互,并且如果输入 源的 targetRaySpace 与作为最顶层 事件目标的跨源内容相交,则 UA 必须启用 WebXR Device API § 13.4.3 Limiting 数据调整,并为与该输入源关联的 XRSpace 相应地填充姿态,将 limit 布尔值视为 true。此外, 当姿态受到限制时,UA 不得更新此输入源的游戏手柄数据。

注: 当姿态以这种方式受到限制时, 应用不会接收到控制器或其定向射线的姿态更新。UA 负责根据需要绘制 指针射线或其他适当的可视化,以启用交互。

注: 限制更新游戏手柄数据 旨在避免从与跨源内容的交互中向应用泄露信息。 例如,如果输入源的主操作使用模拟扳机,并且 主操作在某个扳机阈值处发生,则即使相应事件被阻止,应用也可以从 扳机值推断用户何时开始和结束主操作。另一个 例子是,设备使用触控板或摇杆在 DOM 内容中输入文本,读取 轴值将允许应用推断正在输入的文本。

如果主操作在跨源内容内结束,则 UA 必须将主操作视为已取消,并且不得发送 select 事件。UA 必须使用进入跨源内容之前可用的最后一个姿态发送 selectend 事件,因为它将姿态视为受限制。

如果输入是瞬态输入源,并且如果瞬态操作在跨源内容内开始,则用户代理必须延迟 添加输入源,直到输入位置移出跨源 内容。如果瞬态操作在仍位于跨源 内容内时结束,则不会添加该瞬态输入源。

注: 在使用 screen 模式 输入的手持 AR 设备上,这意味着停留在跨源内容内的触摸不会创建输入源或 关联的 XR 输入事件。如果拖动移动在跨源内容内开始,则输入源会在触摸位置离开跨源内容的位置 创建,并像往常一样发出可取消的 beforexrselect 事件。

6. 安全、隐私和舒适性考量

6.1. 受保护功能

DOM 覆盖层本身不会引入任何新的敏感信息。但是,由于它组合了 现有技术,因此务必确保这种组合不会导致任何意外的 交互。

此模块的一个主要设计目标是:DOM 覆盖层应尽可能遵循 2D 内容的既有语义。具体而言,与跨源嵌入内容相关的信息流应 类似于在 2D 页面上使用 iframe。例如,2D 页面可以在 iframe 中嵌入跨源内容,然后用透明元素覆盖此 iframe。在这种情况下,页面会继续 接收鼠标移动信息,但跨源内容不会接收被覆盖区域内的任何输入事件。 对于 DOM 覆盖层,XR 输入事件数据被视为类似于鼠标移动数据。如果没有跨源内容,或者 跨源内容没有接收输入,则姿态仍可供外层页面使用;但在与跨源内容交互时,姿态会受到限制(被阻止)。

跨源内容可能容易受到点击劫持威胁。当在 DOM 覆盖层中使用 iframe 时,UA 必须 继续应用缓解措施,例如 Content Security Policy 3 § 6.1.5 frame-src。如有必要,为应对特定威胁,UA 可以专门针对 DOM 覆盖层中的跨源内容实施额外限制。

变更

相对于 2021 年 8 月 31 日首次公开工作草案的变更

7. 致谢

以下个人对 WebXR DOM 覆盖层规范的设计作出了贡献:

一致性

文档 约定

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

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

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

这是一个资料性示例。

资料性注释以 “Note” 开头,并通过 class="note" 与规范性文本分隔开, 如下所示:

注,这是一个资料性注释。

一致性 算法

作为算法一部分以祈使语气表述的要求 (例如 "strip any leading space characters" 或 "return false and abort these steps"), 应按引入该算法时所使用的关键字 ("must"、"should"、"may" 等) 的含义来解释。

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

索引

由本 规范定义的术语

由引用 定义的术语

参考文献

规范性参考文献

[CSP3]
Mike West; Antonio Sartori. Content Security Policy Level 3. 2024 年 9 月 9 日. WD. URL: https://www.w3.org/TR/CSP3/
[CSS-POSITION-4]
CSS Positioned Layout Module Level 4. 编辑草案. URL: https://drafts.csswg.org/css-position-4/
[CSS21]
Bert Bos; et al. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification. 2011 年 6 月 7 日. REC. URL: https://www.w3.org/TR/CSS21/
[DOM]
Anne van Kesteren. DOM Standard. 现行标准. URL: https://dom.spec.whatwg.org/
[FILTER-EFFECTS-2]
Filter Effects Module Level 2. 编辑 草案. URL: https://drafts.fxtf.org/filter-effects-2/
[FULLSCREEN]
Philip Jägenstedt. Fullscreen API Standard. 现行标准. URL: https://fullscreen.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. 现行标准. URL: https://html.spec.whatwg.org/multipage/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. 1997 年 3 月. 最佳当前实践. URL: https://datatracker.ietf.org/doc/html/rfc2119
[SELECTORS-4]
Elika Etemad; Tab Atkins Jr.. Selectors Level 4. 2022 年 11 月 11 日. WD. URL: https://www.w3.org/TR/selectors-4/
[UIEVENTS]
Gary Kacmarcik; Travis Leithead. UI Events. 2024 年 9 月 7 日. WD. URL: https://www.w3.org/TR/uievents/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. 活 标准. URL: https://webidl.spec.whatwg.org/
[WEBXR]
Brandon Jones; Manish Goregaokar; Rik Cabanier. WebXR Device API. 2024 年 8 月 21 日. CR. URL: https://www.w3.org/TR/webxr/
[WEBXR-DOM-OVERLAYS-1]
Piotr Bialecki. WebXR DOM Overlays Module. 2022 年 11 月 17 日. WD. URL: https://www.w3.org/TR/webxr-dom-overlays-1/

IDL 索引

partial interface mixin GlobalEventHandlers {
  attribute EventHandler onbeforexrselect;
};

partial dictionary XRSessionInit {
  XRDOMOverlayInit? domOverlay;
};

partial interface XRSession {
  readonly attribute XRDOMOverlayState? domOverlayState;
};

dictionary XRDOMOverlayInit {
  required Element root;
};

enum XRDOMOverlayType {
  "screen",
  "floating",
  "head-locked"
};

dictionary XRDOMOverlayState {
  XRDOMOverlayType type; 
};

MDN

Element/beforexrselect_event

In only one current engine.

FirefoxNoneSafariNoneChrome83+
Opera?Edge83+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

XRSession/domOverlayState

In only one current engine.

FirefoxNoneSafariNoneChrome83+
Opera?Edge83+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?