1. 引言
本节为非规范性内容。
操作系统通常允许用户将多个屏幕连接到单一设备上,并以虚拟方式排列这些屏幕,从而扩展整体的视觉工作区域。
多种应用程序会利用平台工具在这种多屏环境中放置其内容,但 Web 应用开发者受限于现有 API,这些 API 通常是围绕单一屏幕的使用设计的。
随着多屏设备和应用成为用户体验中越来越常见且重要的一部分,提供信息和工具让 Web 开发者能够充分利用扩展的视觉环境变得更加重要。
本规范按步骤扩展了 Window、
Screen
和 FullscreenOptions
等 API,并引入了新的 ScreenDetails
与 ScreenDetailed
接口。这些改变允许 Web 应用通过在特定屏幕上放置内容,提供引人入胜的多屏体验。
1.1. 动机与用例
本规范旨在为拥有多屏设备的 Web 应用用户带来更好的体验。以下用例为设计提供了参考:
-
幻灯片应用在投影仪上展示演示内容,同时在笔记本屏幕上显示演讲者备注。
-
金融应用在多个显示器上打开仪表盘窗口。
-
医疗应用在高分辨率灰阶显示器上打开图像(如 X 光片)。
-
创作类应用在其他屏幕上显示辅助窗口(如调色板)。
-
会议室应用在触控设备上显示控件,在电视上播放视频。
-
游戏、标牌、艺术等多种类型的应用中的多屏布局。
-
当窗口横跨多个屏幕时,站点优化内容和布局。
1.2. 用法概览
为支持多屏体验,该 API 允许 Web 应用:
-
检测设备是否存在多个屏幕
-
请求在特定屏幕上放置内容所需的信息
-
检测屏幕的添加或移除
-
检测当前屏幕或其属性的变化
-
将某个元素以全屏方式显示在特定屏幕上
-
将窗口放置在特定屏幕上
-
通过单次用户操作启动多屏体验
API 用法的一个基本示例如下:
// Detect if the device has more than one screen. if ( window. screen. isExtended) { // Request information required to place content on specific screens. const screenDetails= await window. getScreenDetails(); // Detect when a screen is added or removed. screenDetails. addEventListener( 'screenschange' , onScreensChange); // Detect when the current \`ScreenDetailed\` or an attribute thereof changes. screenDetails. addEventListener( 'currentscreenchange' , onCurrentScreenChange); // Find the primary screen, show some content fullscreen there. const primaryScreen= screenDetails. screens. find( s=> s. isPrimary); document. documentElement. requestFullscreen({ screen: primaryScreen}); // Find a different screen, fill its available area with a new window. const otherScreen= screenDetails. screens. find( s=> s!== primaryScreen); window. open( url, '_blank' , \`left= ${ otherScreen. availLeft} ,\` + \`top= ${ otherScreen. availTop} ,\` + \`width= ${ otherScreen. availWidth} ,\` + \`height= ${ otherScreen. availHeight} \`); } else { // Detect when an attribute of the legacy \`Screen\` interface changes. window.screen.addEventListener('change', onScreenChange); // Arrange content within the traditional single-screen environment... }
1.2.1. 检测多屏存在
支持多屏体验的核心问题之一,是设备是否有多个屏幕可用于放置内容。这些屏幕可以是设备的内置显示(如笔记本的显示屏)、通过有线连接(如电脑通过 HDMI 连上显示器)、通过其他方式连接(如 Mac 和 iPad 的
Sidecar 功能),或者通过显示虚拟化实现。isExtended
布尔值用于此判断,对安全上下文开放且无需权限提示。
if ( screen. isExtended) { // Offer multi-screen controls for the user. }
1.2.2.
检测 Screen
属性变化
监听传统 Screen
属性变化对内容适配很有用,即使是在单屏设备上。此外,监听 isExtended
有助于检测单屏与多屏配置之间的切换。为避免轮询,change
事件会在 Screen
对象上触发:
screen. addEventListener( 'change' , e=> { // An attribute of the legacy \`Screen\` interface has changed. });
1.2.3. 请求详细屏幕信息
可通过 getScreenDetails()
方法请求设备使用的屏幕详细信息。该方法可能会弹出权限请求。得到的 ScreenDetails
对象允许开发者枚举所有屏幕、检查其属性并监听变化。
try { // Request screen details and process the information immediately. const screenDetails= await window. getScreenDetails(); processScreenDetails( screenDetails); // Process updated screen details when the set of screens change. screenDetails. onscreenschange= () => { processScreenDetails( screenDetails); }; } catch ( err) { console. error( err); // Handle denied permission and other errors. } function processScreenDetails( screenDetails) { // Build a UI listing screens, using assumed helpers. clearScreenList(); screenDetails. screens. forEach( screen=> { addToScreenList({ name: screen. label, screen: screen}); // Process updated screen details when a particular screen's details change. screen. onchange= () => { processScreenDetails( screenDetails); }; }); selectCurrentInScreenList( screenDetails. currentScreen); }
1.2.4. 在特定屏幕上放置全屏内容
一个常见的多屏用例是在特定屏幕上以全屏形式展示部分内容。屏幕可以通过交互选择,也可以基于屏幕属性或先前选择自动选出。一旦选定屏幕,可作为参数传递给 requestFullscreen()
方法。
// Call an assumed helper that returns a selected \`ScreenDetailed\` instance. const screenDetailed= getScreenForSlideshow(); // Request that a particular element be shown fullscreen on the selected screen. slideshowElement. requestFullscreen({ screen: screenDetailed});
1.2.5. 在特定屏幕上放置窗口
另一个常见的多屏用例是在特定屏幕上放置窗口。这可以结合 ScreenDetailed
接口提供的坐标,与现有 open()
和 moveTo()
方法完成。
function openCenteredWindow( url, screenDetailed, w, h) { // Compute coordinates centering the window on the target screen. const l= screenDetailed. left+ Math. round( screenDetailed. width- w) / 2 ; const t= screenDetailed. top+ Math. round( screenDetailed. height- h) / 2 ; // Open the window with the requested dimensions. return window. open( url, '_blank' , \`left= ${ l} ,top= ${ t} ,width= ${ w} ,height= ${ h} \`); }
1.2.6. 启动多屏体验
一个常见的多屏需求是通过用户的单次激活启动丰富的多屏体验。具体方案之一,是允许站点可在一次用户操作中,既 § 1.2.4 在特定屏幕上放置全屏内容,又 § 1.2.5 在特定屏幕上放置窗口。实现方式是在多屏设备上,先针对特定屏幕请求全屏,再在另一屏幕打开弹窗窗口,两步均在一个事件监听器内完成。
initiateMultiScreenExperienceButton. addEventListener( 'click' , async () => { // Find the primary screen, show some content fullscreen there. const primaryScreen= screenDetails. screens. find( s=> s. isPrimary); await document. documentElement. requestFullscreen({ screen: primaryScreen}); // Find a different screen, fill its available area with a new window. const otherScreen= screenDetails. screens. find( s=> s!== primaryScreen); window. open( url, '_blank' , \`left= ${ otherScreen. availLeft} ,\` + \`top= ${ otherScreen. availTop} ,\` + \`width= ${ otherScreen. availWidth} ,\` + \`height= ${ otherScreen. availHeight} \`); });
2. 概念
本规范中的概念基于 CSSOM-View-1 工作草案、CSSOM-View-1 编辑者草案、[HTML],以及 [Fullscreen]。
2.1. 屏幕
承载用户代理的设备拥有单个 screen 或多个 screens,用于显示视觉内容。screens 的集合可能随用户代理运行期间设备硬件或软件配置的变更而变化。
注: 屏幕配置变化的一些基本例子包括:通过 HDMI 线把电视或投影仪接到笔记本电脑,合上笔记本盖从而关闭内置 LCD 屏,更改接入 LCD 显示器的分辨率等。
一个 screen 拥有 设备像素比,类似 Window
的
devicePixelRatio
,其值计算方式如下:
一个 screen 拥有 方向,定义见 [screen-orientation]。
一个 screen 拥有 标签,即用于帮助用户区分识别屏幕的有意义描述字符串。
注: 标签 可以是用户代理选择的任意字符串。它可能描述屏幕与设备的关系,如 "internal" 或
"external";也可能包含分辨率信息,如 "640×480";还可能包含硬件型号,如
"Acme Telletube 1000x"(取自 VESA E-EDID 数据)、区分编号如
"screen 1" 与
"screen 2",甚至全部兼有。如果底层显示详情未知,或用户代理选择隐藏这些信息,也可为空串。应用不能假定标签一定包含设备类型、型号、尺寸、密度等特定信息。
虽然许多屏幕属性都可能被用于 主动指纹识别,但 标签 所用字符串尤其应谨慎,尽量降低唯一性。例如,不应将设备序列号包含其中。
2.2. 屏幕像素
一个屏幕具有像素,像素是屏幕中可以直接编程的最小组件。每个像素显示一种颜色。
注:在液晶显示屏(LCD)上,每个像素由三个分量组成,每个分量为(红、绿、蓝)可变强度的光。关于像素分量(亚像素渲染)的讨论不在本规范范围内。
注:有些屏幕可以被配置为以与物理硬件固有排列不同的分辨率进行内容显示;例如,硬件分辨率为2560×1440的显示器可被设备设置为1920×1080的显示分辨率。
一个像素具有色深,即用于表示它能显示颜色的位数。
2.3. 屏幕区域
注:格网大小通常表示为<宽度>×<高度>。例如,1920×1080的屏幕区域即宽度为1920像素、高度为1080像素的格网。
注:如CSSOM View § 2.3 Web公开屏幕信息 所述,UA 可选择隐藏显示设备屏幕的信息,以保护用户隐私。在此情况下,屏幕区域可等同于视口。
2.4. 可用屏幕区域
一个屏幕具有可用屏幕区域,是屏幕区域的矩形子集,操作系统允许Web应用窗口放置在其中。该矩形的边缘与屏幕区域边平行。此区域不包括任何被操作系统保留用于自身 UI 元素(如任务栏、菜单栏)的屏幕区域部分。等价于特定屏幕的Web公开可用屏幕区域。
2.5. 虚拟屏幕排列
设备有一个虚拟屏幕排列,用于定义组成设备整体视觉环境的屏幕的相对位置。排列通常在一个二维平面上组成,向右和向下 (x, y) 坐标分别递增,原点为多屏原点。多屏原点是实现自定义的点,定义了虚拟屏幕排列的(0, 0)坐标。
常见做法是将多屏原点设置在主屏幕的左上角,但它也可以是虚拟屏幕排列内的任意点。每个屏幕的屏幕区域都是对虚拟屏幕排列矩形子集的可视。
下图展示了多屏幕在虚拟屏幕排列中的一些排列示例,以及一些可能的多屏原点:
注:Second Screen Community Group 的 Form Factors Explained 草案报告探讨了相关术语和概念模型。
2.6. 屏幕位置
一个屏幕具有屏幕位置,即其屏幕区域在虚拟屏幕排列中相对于多屏原点的(x, y)坐标。坐标可为负数,通常写作(x, y)。
2.7. 可用屏幕位置
一个屏幕具有可用屏幕位置,即其可用屏幕区域在虚拟屏幕排列中相对于多屏原点的(x, y)坐标。坐标可为负数,通常写作(x, y)。
2.8. 主屏幕
注:主屏幕通常承载操作系统的任务管理界面,如 Windows 任务栏或 macOS Dock。
一个屏幕被指定为主或副的身份可能会在用户代理运行时发生变化。
注:大多数操作系统允许用户通过管理界面(如 Windows 控制面板和 macOS 偏好设置)选择主屏幕。
2.9. 内置屏幕
每个屏幕可以被指定为内置或外接。
外接屏幕是由提供其视觉输出的设备单独制造的。一块外接屏幕可以从一个设备上断开连接再连接到另一设备上,这很常见。
注:例如,一台台式机可能通过HDMI线将其视觉输出显示在外接屏上。HDMI线可随时插拔,计算机会随硬件变更调整视觉环境。
内置屏幕通常在设备生产时就被装配上。内置屏不是给用户拆卸用的。但内置屏幕 依然可以在用户代理运行时被启用或禁用。
注:例如,笔记本合盖时会禁用内置屏幕及输入设备,用户可以通过外接屏幕和输入设备继续使用。关闭时禁用的内置屏幕在合盖期间不会作为设备使用的屏幕上报。
2.10. 当前屏幕
在Window上下文中运行的脚本可以访问screen属性。此Screen对象反映了当前屏幕的属性,即当前在该屏幕上展示窗口的屏幕。
注:在许多操作系统下,窗口可能横跨不同属性的多个屏幕,也可能处于“隐藏”状态不显示在任何屏幕上。操作系统和UA通常为给定Window确定一个标准屏幕,比如与窗口交集面积最大者。
2.11. 可观察屏幕属性
屏幕的基础可观察属性包括:
屏幕的进阶可观察属性包括:
3. API
3.1. 对Screen
接口的扩展
CSSOM View 模块
规范定义了 Screen
接口,本规范对此进行扩展:
- window . screen .
isExtended -
如果设备的视觉输出延伸到多个屏幕,则返回
true。 - window . screen .
onchange -
当窗口的屏幕或其属性发生变化时触发。
partial interface Screen /* : EventTarget */ { [SecureContext ]readonly attribute boolean isExtended ; [SecureContext ]attribute EventHandler onchange ; };
让 Screen
继承自 EventTarget
,详见 CSSOM View § 4.3 The
Screen Interface。
3.1.1.
isExtended
属性
isExtended getter 步骤如下:
3.1.2.
onchange
属性
onchange 属性是事件处理IDL属性,其事件处理类型为change。
当Window
window的当前屏幕的任何基础可观察属性发生变化时,在window的相关全局对象上使用window placement task
source排队一个全局任务,触发一个事件,事件名为change,目标是由window的Screen属性引用的对象。
3.2. 对 Window
接口的扩展
[HTML] 标准定义了
Window
接口,本规范对此进行扩展:
- window .
getScreenDetails() -
返回一个 promise,当其完成时会获得一个关于设备屏幕信息的
ScreenDetails对象。如果权限被拒,promise 将被拒绝。
partial interface Window { [SecureContext ]Promise <ScreenDetails >getScreenDetails (); };
3.2.1. getScreenDetails()
方法
getScreenDetails()
方法是异步完成的,其工作会被排入 window placement task source。
Window
的实例创建时包含名为 [[screenDetails]] 的 内部槽位,初始值为 undefined。
getScreenDetails() 方法步骤如下:
-
令 promise 为 新建的 promise。
-
如果this的相关全局对象的相关文档无权限使用名为"
window-management"的策略受控特性,则用"NotAllowedError"DOMException拒绝 promise,并终止步骤。 -
如下步骤并行执行:
-
令 permissionState 为请求使用权限 "
window-management" 的结果。 -
排队全局任务到this 的相关全局对象,用 window placement task source 执行以下步骤:
-
如果 permissionState 为 "
denied", 则用"NotAllowedError"DOMException拒绝 promise,并终止步骤。 -
如果this.
[[screenDetails]]为undefined,则设置 this.[[screenDetails]]为新的ScreenDetails对象。 -
解决 promise,值为 this.
[[screenDetails]]。
-
-
-
返回 promise。
3.2.2. Window
属性和方法定义变更
如下 Window
属性和方法定义被更新为返回和解释相对于多屏原点的值:
-
screenX和screenLeft属性必须返回客户区窗口左边相对于多屏原点的 x 坐标(单位为CSS 像素),如无返回0。 -
screenY和screenTop属性必须返回客户区窗口顶部相对于多屏原点的 y 坐标(单位为CSS 像素),如无返回0。
3.2.3. Window.open()
方法定义变更
Window
实例创建时有个名为 [[targetScreenFullscreen]] 的内部槽,该槽在数据模型上等价于上次激活时间戳。其对应于 DOMHighResTimeStamp
类型值,除了两种特殊情况:正无穷表示该窗口从未被激活,负无穷表示用户激活门控 API(见 HTML
§ 6.4.3 用户激活门控 API)消耗了该窗口的上次激活。初始值为正无穷。
Window.open()
方法及其中调用方法的步骤被更新,可选择性地:
-
当瞬时激活状态要求被放宽(即 当前高精度时间 大于等于 相关全局对象的 this.
[[targetScreenFullscreen]]且小于 this.[[targetScreenFullscreen]]加 瞬时激活时间时。 -
在消耗用户激活步骤后,立即将 this.
[[targetScreenFullscreen]]设为负无穷。
3.3.
ScreenDetails
接口
- screenDetails .
screens -
返回一组
ScreenDetailed对象,用于描述每一个屏幕。 - screenDetails .
currentScreen -
返回一个用于描述当前屏幕的
ScreenDetailed对象。该对象描述的 屏幕 与Window.screen相同,但信息更丰富。 - screenDetails .
onscreenschange - screenDetails .
oncurrentscreenchange
[Exposed =Window ,SecureContext ]interface :ScreenDetails EventTarget {readonly attribute FrozenArray <ScreenDetailed >screens ;readonly attribute ScreenDetailed currentScreen ;attribute EventHandler onscreenschange ;attribute EventHandler oncurrentscreenchange ; };
3.3.1. screens
属性
screens getter 步骤如下:
3.3.2. currentScreen
属性
currentScreen getter 步骤为返回 ScreenDetailed
对象,该对象在 screens
中,代表与 当前屏幕 相关联的 Window
对象。
注: 哪个 ScreenDetailed
对象在 screens
中代表某个 Window
的 当前屏幕,通常由操作系统和用户代理定义。这与
Window.screen
一致,即窗口的规范屏幕,例如与窗口交集区域最大者。
注: currentScreen
保证可以通过 === 与 screens
中的某项比较相等,便于如 screenDetails.screens.find(s => s !== screenDetails.currentScreen); 这类比较。因此 currentScreen
不会被标记为 [SameObject]。类似地,添加在 change
上的事件监听器仅会通知对应 screen 的变化,而监听 currentscreenchange
的监听器会收到当前 screen (即窗口切换到不同屏幕后) 的变化事件。
3.3.3. onscreenschange
属性
onscreenschange 属性是事件处理 IDL 属性,其事件类型为 screenschange。
当某 ScreenDetails
对象 screenDetails 的 screens
集合发生变化时,需在 screenDetails 的相关全局对象上用 window placement task
source 触发 screenschange 事件。
3.3.4. oncurrentscreenchange
属性
oncurrentscreenchange 属性是事件处理 IDL 属性,其事件类型为 currentscreenchange。
当某 Window
window 的当前屏幕由一个
screen
变为另一个(例如窗口被移动到不同的显示屏),或 window 的 当前屏幕 的任何 基础可观察属性
或 高级可观察属性发生变化时,要在 window 的相关全局对象上用 window placement task
source 触发 currentscreenchange 事件,目标为
ScreenDetails
对象(存储在 window 的内部槽 [[screenDetails]]
中)。
3.4.
ScreenDetailed
接口
ScreenDetailed
对象表示一个 屏幕。
- screenDetailed .
availLeft -
返回可用屏幕区域左边缘到 多屏原点的距离。
- screenDetailed .
availTop -
返回可用屏幕区域顶边缘到 多屏原点的距离。
- screenDetailed .
left -
返回屏幕区域左边缘到 多屏原点的距离。
- screenDetailed .
top -
返回屏幕区域顶边缘到 多屏原点的距离。
- screenDetailed .
isPrimary -
返回该屏幕是否被操作系统标记为“主”屏幕(否则为“副”屏幕)。
- screenDetailed .
isInternal -
返回该屏幕是否为内置于设备中的“内置”面板,如笔记本显示屏(否则为“外接”,如连接的显示器)。
- screenDetailed .
devicePixelRatio -
返回物理像素与逻辑像素之间的比例。
- screenDetailed .
label -
由用户代理和操作系统决定的、用户友好的屏幕标签。
[Exposed =Window ,SecureContext ]interface :ScreenDetailed Screen {readonly attribute long availLeft ;readonly attribute long availTop ;readonly attribute long left ;readonly attribute long top ;readonly attribute boolean isPrimary ;readonly attribute boolean isInternal ;readonly attribute float devicePixelRatio ;readonly attribute DOMString label ; };
availLeft getter 步骤为返回 可用屏幕位置 的 x
坐标。
availTop getter 步骤为返回 可用屏幕位置 的 y
坐标。
left getter 步骤为返回 屏幕位置 的 x 坐标。
top getter 步骤为返回 屏幕位置 的 y 坐标。
isPrimary getter 步骤为:如 this screen 是 主 屏幕,返回
true,否则为 false。
isInternal getter 步骤为:如 this screen 为 内置,返回 true,否则为 false。
devicePixelRatio getter 步骤为返回 设备像素比。
label getter 步骤为返回 标签。
3.4.1. onchange
属性
onchange 属性是继承自 onchange
的属性,来自 Screen。
当 ScreenDetailed
对象 screenDetailed 所代表的 屏幕 的任一 基础可观察属性 或 高级可观察属性变更时,要在 screenDetailed 的相关全局对象上用 window placement task
source 触发 change
事件。
3.5.
对 FullscreenOptions
的扩展
partial dictionary FullscreenOptions {ScreenDetailed screen ; };
可选成员 FullscreenOptions
的 screen,表示应用希望将元素全屏显示在特定 屏幕 上。用户代理总是可优先考虑用户偏好而非应用优先级。默认值 undefined 表示无应用偏好。
3.5.1. Element.requestFullscreen()
方法定义变更
Element.requestFullscreen()
方法的步骤可选地:
-
当调整
pendingDoc的 顶级浏览上下文的 活动文档视口时,如options["screen"] 有指定,可将视口移动到指定 屏幕。 -
如
options["screen"] 指定的ScreenDetailed对象且其isExtended为 true,则将本对象的[[targetScreenFullscreen]]内部槽设置为当前高精度时间。
3.6. 权限 API 集成
本规范定义了一个默认强大特性,其名称为 name
"window-management"。
[permissions] API 提供了统一方式供网站查询其权限状态。
注: 本文档之前公开的版本使用了权限名
"window-placement"。用户代理应谨慎迁移到新的权限字符串 "window-management"。参见
#114。
将 window-management
添加到 [permissions] 注册表。
定义当权限被撤销时缓存对象和方法步骤的行为。(见 #80)
3.7. 权限策略集成
本规范定义了一个策略受控特性,字符串为 "window-management",用于控制是否允许 isExtended、
getScreenDetails
及相关功能的使用。该特性的默认允许列表为 'self'。参见 [permissions-policy] 及其 Experimental
Features 列表。
注: 一个 document
的权限策略决定了该文档内的任何内容是否能从 isExtended
获取有效值、访问 ScreenDetails
或在特定屏幕上放置内容。如被禁用,isExtended
返回 false,getScreenDetails
返回的 promise 会被拒绝,试图将内容放到特定屏幕会被限定在 当前屏幕。
适当时将 window-management
移至 Proposed
或 Standardized
列表。
4. 安全性考量
本规范使站点可以将内容放置在特定屏幕上,这可能带来有限的新安全风险:
-
站点可能试图在意外的屏幕上突出显示敏感内容
-
站点可能试图秘密地在不显眼的屏幕上显示不良内容,例如:
-
站点可能通过将用户的注意力吸引到特定屏幕上,并利用那里的交互信号,在其他较少被注意的屏幕上显示带有欺骗性的内容,从而试图伪造操作系统、浏览器或其他站点进行钓鱼攻击
-
站点可能试图以其他欺骗性、滥用性或令人烦恼的方式,将内容放置在特定屏幕上
为帮助缓解这些风险,跨屏幕放置能力要求在安全上下文中获得明确许可,并受 [permissions-policy] 约束,默认防止第三方访问。
用户代理可以检测跨屏幕放置请求,并采取措施保护用户免受潜在的滥用。例如,当站点将内容放置在另一个屏幕上,或者窗口在跨屏幕放置后获得用户关注时,用户代理可以显示明显的安全界面。此外,跨屏幕放置请求可以被拒绝或限制在 当前屏幕,以符合一些用户代理的现有行为。
其他补充说明:
-
一些用户代理已经不会将窗口放置请求限制在 当前屏幕;它们将
open()和moveTo()的坐标解释为相对于 多屏原点,并允许将窗口放置在非 当前屏幕。 -
瞬时用户激活通常已是
requestFullscreen()和open()所需,但moveTo()、moveBy()、resizeTo()、 以及resizeBy()并不需要。 -
将内容放到非 当前屏幕通常不会带来额外的点击劫持风险,因为用户的光标或手指很可能与 当前屏幕共现,而不会出现在另一个屏幕上。
-
将传统放置能力与指定权限绑定是可行的。
请参阅以下关于安全性考量的深入探讨:
5. 隐私性考量
本规范向站点暴露了关于设备连接屏幕的新信息,这可能带来有限的新隐私风险。此额外信息增加了设备的 指纹识别 面,尤其是在屏幕配置非典型的设备上。
为缓解这些风险,新信息被压缩到常见放置场景所需的最小值,大部分访问需要在安全上下文中明确授权,并受到 [permissions-policy] 约束,默认防止第三方访问。暴露出来的屏幕列表有明确顺序,以减少互操作性问题并缓解指纹化。用户代理通常可以检测并干预站点请求新信息的行为。
Screen.isExtended 布尔值无需明确权限检查即可暴露,因为这一最小的单比特信息支持一些关键特性(例如显示/隐藏“在另一屏幕显示”等多屏 UI
入口),提示授权会打扰用户,并有助于避免对单屏用户无意义的提示。这通常符合 TAG 设备枚举设计原则(参见 Web Platform Design Principles
§ device-enumeration)。
很多用户代理已经通过 window.screen.availLeft|Top >> 0 向位于副屏上的窗口有效暴露了多屏存在。脚本访问这个比特是可被用户代理侦测并阻断的 主动指纹信号。此外,不限制未授权窗口放置请求在 当前屏幕 的用户代理,会使攻击者有机会在其他屏幕进行编程放置,从而暴露
window.screen 的信息。
新 Screen.onchange 事件带来的风险是可使 短暂指纹 更容易实现,但脚本本就可以通过轮询
window.screen 达到类似效果。该风险可通过在文档隐藏期间延迟事件派发部分缓解。
我们曾考虑过赋予站点更少能力的 API 设计,但这会降低用户和开发者体验(例如每次都让用户选屏,开发者申报屏幕优先级)。对于在任意已连接屏幕上非全屏放置应用窗口,几乎不存在可替代方案。所指定 API 形态是对现有 API 支持完整多屏环境的自然扩展。将来可能补充仅公开有限多屏信息的能力,让站点可自愿减少信息暴露。
该 API 设计允许用户代理采用新型访问模型有选择地暴露屏幕,例如仅公开由用户指定的屏幕信息与放置能力。
其他补充说明:
-
将传统的屏幕与窗口信息访问能力纳入指定权限管理是可行的。
请参阅以下关于隐私性考量的深入探讨:
6. 可访问性考量
本规范使站点可以将内容放置在特定屏幕,这可能带来有限的新可访问性风险。视觉展示、非视觉渲染、以及辅助技术对内容本身的影响,一般不因内容放置在哪块屏幕而发生本质性变化。不过,随着内容可放置区域的扩大,程序化放置内容的现有可及性风险可能会加剧。关于 默认强大特性权限模型、提示机制、与权限相关的 UI 的现有可访问性考量,对本规范的相关权限同样适用。
目前 API 暴露的结构化屏幕信息(以及其可访问性特性)无被记录的可访问性考量。
7. 国际化考量
当前无被记录的国际化考量。
8. 致谢
特别感谢 Adrienne Walker、 Anssi Kostiainen、 Chris Terefinko、 Domenic Denicola、 Jonathan Garbee、 Kenneth Rohde Christiansen、 L. David Baron、 Lukasz Olejnik、 Marijn Kruisselbrink、 Matt Giuca、 Michael Ketting、 Nadav Sinai、 Peter Linss、 Reilly Grant、 Staphany Park、 Theresa O’Connor、 Thomas Nattestad、 Thomas Steiner,以及 Victor Costan 对本规范的撰写做出的帮助。
特别鸣谢 Tab Atkins, Jr. 创建并维护了 Bikeshed(本规范编写所用工具),以及他在规范撰写方面的指导。