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 覆盖层元素上派发一个类型为 beforexrselect
的 XRSessionEvent。
partial interface mixin GlobalEventHandlers {attribute EventHandler ; };onbeforexrselect
此事件是一个类型为 beforexrselect
的 XRSessionEvent,
它会冒泡、可取消且是组合的。其 target
元素是被 targetRaySpace
相交的最顶层事件目标,且要么是 DOM 覆盖层元素的后代,要么是 DOM 覆盖层元素本身。
通过调用 preventDefault()
取消此事件,会抑制输入源通常会为此主操作生成的默认 WebXR 输入事件。对于此
交互序列,不会触发 selectstart、
selectend
和 select 事件。
注: 未来的 WebXR 模块可以定义会受 取消此事件影响的其他事件或 WebXR 输入相关数据,例如抑制来自瞬态输入源命中测试订阅的结果。
此事件以及事件处理器所采取的操作不会影响 DOM 事件处理,并且不会 与 DOM 事件派发同步。用户的操作会单独生成适当的 DOM 事件,例如 `"pointerdown"`,并且这些 DOM 事件可能发生在对应的 beforexrselect 事件之前或之后。这 与 beforexrselect 事件是否被取消无关,并且独立于 XR 输入事件处理器中采取的任何后续操作。
注: 此事件为应用提供了一种方式, 使其可在用户与 DOM UI 交互时抑制重复的 XR 输入事件。由于这是一个冒泡 事件,应用可以在适当的容器元素上注册处理器,从而有效地将 DOM 覆盖层的区域 标记为阻止 XR 输入。这与 DOM 元素的视觉不透明度无关。可以 显示非交互式的不透明或半透明 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 集成
此模块扩展了 XRSessionInit
和 XRSession
的定义,
并修改了 XRInputSource
事件的行为。
3.1. XRSessionInit
此模块引入字符串 dom-overlay,作为新的有效
特性描述符,用于沉浸式会话的 requiredFeatures
或 optionalFeatures
序列。
如果某设备能提供一种方式,使用户在沉浸式会话期间查看 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
必须在开始输入处理之前运行以下步骤,以决定是否将其视为主操作:
-
如果在输入设备的主 操作被触发时,输入源的
targetRaySpace与 DOM 覆盖层相交:-
排队一个任务,以便在 DOM 覆盖层
root内被targetRaySpace相交的最顶层事件目标上,使用XRSessionEvent触发一个事件,该事件名为 beforexrselect, 并将target设置为该元素。此事件会冒泡、可取消且是组合的。 -
按如下方式检查应如何处理 XR 输入:
-
注: 实际上,取消 beforexrselect 事件会
抑制 XR 输入 select 事件;不会为此操作生成 selectstart、
selectend
或 select。对于瞬态
输入源,仍会生成 inputsourceschange
事件,但取消 beforexrselect
事件会导致该操作被视为辅助操作,类似于次要手指输入。
4. 初始化
应用必须通过 domOverlay
字典为 DOM 覆盖层提供配置。
dictionary {XRDOMOverlayInit required Element root ; };
root 属性指定将作为 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 覆盖层正在如何显示。该值在会话期间必须保持不变。
-
screen覆盖层类型表示 DOM 覆盖层 元素覆盖基于屏幕的设备(例如手持 AR)的整个物理屏幕。其 视觉范围必须与用于XRWebGLLayer渲染的XRViewport相匹配。对于单目显示,这是单个视口。立体显示屏会 提供两个视口,在这种情况下,DOM 覆盖层必须在与物理屏幕位置相匹配的 Z 位置渲染, 在双眼视图中表现相同。 -
floating覆盖层类型表示 DOM 覆盖层 显示为空间中的浮动矩形。此矩形在世界空间中的初始位置由 UA 决定,并且 UA 可以在会话期间移动它以保持其在视野内,或支持 用户发起的手动放置。 -
head-locked覆盖层类型表示 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 覆盖层规范的设计作出了贡献:
-
Brandon Jones (Google)
-
Nell Waliczek (Amazon [Microsoft until 2018])