Window Management API:多屏边界
使用 Window Management 时明确权限、用户激活、拓扑变化处理与隐私安全的单屏回退。
BotBrowser Team
Window Management API 允许 Web 应用在浏览器授权后了解多个可用屏幕并选择窗口位置。它不是显示器清单,也不是位置身份信号。连接、移除、锁定、缩放或重新配置显示器都会改变几何信息,操作系统也可能拒绝或调整请求位置。BotBrowser 受控上下文可以运行获授权页面,从声明的用户操作请求访问,并在 runtime 暴露 API 时记录可见的屏幕与窗口结果;BotBrowser 不能制造第二块物理屏幕、绕过浏览器流程授予权限、保证原生窗口位置,也不能从几何信息推断用户位置。相邻主题可参考屏幕与 viewport 属性以及Screen Orientation API 与响应式体验。
TL;DR
- 在安全上下文中检测
getScreenDetails(),从可见用户操作请求访问。 - 把
ScreenDetails.screens、currentScreen和变化事件当作临时拓扑快照。 - 把坐标和尺寸限制在可用工作区内,再验证最终窗口状态。
- 权限、支持或拓扑不可用时,仍保持单屏或页面内路径完整。
- 不要把屏幕数量、几何或排列变成用户、设备或位置身份。
目录
在用户边界请求屏幕详情
Window Management 规范定义 Window.getScreenDetails() 和 ScreenDetails。MDN Window Management API 参考说明接口与可用性。先确认接口存在,在安全上下文中运行,并且只有可见功能需要时才请求 window-management 权限。
Chrome Window Management 指南展示了可选流程。权限可能被拒绝或策略阻止。单窗口体验必须在这些情况下仍然完整。让按钮或键盘命令解释用途,不要仅因页面加载就请求。
const topologyState = {
phase: 'idle',
outcome: 'unavailable',
screenCount: 0,
sequence: 0,
};
screenCount 是本地决策输入,不是配置档案属性。sequence 用于拓扑变化后丢弃旧结果。不要把设备名、完整坐标历史或屏幕清单和账号一起保存。控件必须有可访问名称、键盘操作、焦点管理和单窗口路径。
把拓扑与位置建模为变化状态
ScreenDetails.screens 是当前快照,currentScreen 表示当前窗口所在屏幕。连接、移除、分辨率或缩放都会改变集合。每个变化事件都应刷新状态,不保证旧位置仍然有效。重新选择候选、计算工作区并验证结果。
位置只是请求。window.open() 可能被弹窗规则阻止、限制尺寸或由窗口管理器调整。使用明确策略:
| 结果 | 位置动作 | 可见契约 | 恢复 |
|---|---|---|---|
| API 或权限不可用 | 留在当前窗口 | 页面内容仍完整 | 仅从新操作再次请求 |
| 当前只有一块屏幕 | 使用当前工作区 | 说明不需要额外窗口 | 保留单屏路径 |
| 多屏且详情新鲜 | 选择有界候选 | 告知打开位置 | 验证窗口并在变化后刷新 |
| 候选屏幕消失 | 保留当前窗口 | 避免突然移动内容 | 用新详情重新选择 |
| 弹窗或位置被拒绝 | 保持当前任务可见 | 说明没有打开新窗口 | 提供页面内继续 |
把坐标限制在 availLeft、availTop、availWidth 和 availHeight,为控件预留边距和最小尺寸。屏幕数量不是身份:两块屏幕可能是虚拟、远程或辅助设置。用序号处理竞态,位置失败时不能关闭原始窗口。
分开处理几何、隐私与无障碍
少见的工作区、缩放和边界组合可能参与指纹。把几何只留在内存,归约成 placed、single-screen 或 fallback,功能结束后删除快照。支持流程可使用 one-screen、topology-changed 等合成类别,不要保存名称、完整坐标或历史。
窗口位置不是显示校准。CSS、缩放、像素比和操作系统缩放都会改变观感。第二窗口需要标题、焦点、键盘操作和返回原窗口的方法。iframe 只应在校验 origin 后接收必要结果。BotBrowser 可以比较获授权的可见结果,但不能制造屏幕、强行授予权限或推断位置。
BotBrowser 支持复现获授权的 Window Management 页面并记录可见的屏幕、位置和回退结果,但不能制造第二块屏幕,也不能保证每个宿主都有相同的原生窗口位置。
用有界 fixture 验证位置
使用带按钮、页面内面板和简短记录的合成页面。只从用户操作请求详情,选择新鲜候选,限制工作区,并确保原始页面始终可用。
const record = { phase: 'idle', outcome: 'unavailable', screenCount: 0, sequence: 0 };
let details;
async function openWorkspace() {
record.sequence += 1;
record.phase = 'pending';
try {
if (!window.isSecureContext || !('getScreenDetails' in window)) {
record.outcome = 'unavailable';
return showInPageWorkspace();
}
details = await window.getScreenDetails();
const screens = [...details.screens];
record.screenCount = screens.length;
const target = screens.find(screen => screen !== details.currentScreen) ?? details.currentScreen;
if (!target) return showInPageWorkspace('no-screen');
const width = Math.max(640, Math.min(960, target.availWidth));
const height = Math.max(480, Math.min(720, target.availHeight));
const child = window.open(
'/workspace',
'workspace',
`left=${target.availLeft},top=${target.availTop},width=${width},height=${height}`
);
record.outcome = child ? 'requested' : 'popup-blocked';
} catch (error) {
record.outcome = error?.name === 'NotAllowedError' ? 'permission-denied' : 'rejected';
} finally {
record.phase = 'idle';
}
}
| Fixture 情况 | 预期结果 | 能证明什么 | 不能证明什么 |
|---|---|---|---|
| API、安全上下文或权限缺失 | unavailable 或 permission-denied | 能力检测与回退所有权 | 没有物理屏幕 |
| 只有一块屏幕 | 单窗口结果 | 单屏路径可用 | 没有虚拟屏幕 |
| 新鲜多屏详情 | 有界几何的 requested | 候选选择与限制 | 系统精确放置 |
| 打开前拓扑变化 | topology-changed、保留页面 | 旧详情不会移动任务 | 变化由哪个进程造成 |
| 弹窗或位置被拒绝 | popup-blocked 或 rejected | 失败可见且可恢复 | 浏览器存在缺陷 |
只记录合成且有界的 browserVersion、runtimePath、screenClass、outcome、geometryBounded、fixtureId 和 sequence。浏览器、显示器、权限或布局变化后重放,并比较第一个不同字段。
Public sources
- Window Management specification
- MDN: Window Management API
- Chrome for Developers: Window Management
- BotBrowser: Advanced features
实践结论
从可见操作请求 Window Management,把屏幕详情当作临时快照,限制并验证窗口位置,同时保留完整的单屏路径。只保存有界结果,不保存拓扑历史,并把几何与身份、位置和校准分开。变化后重放 fixture,从第一个可见变化状态开始排查。
本文属于指南: Web 平台能力面:一致性复核地图