内置浏览器原生页面边界

Electron shell 的 DOM 工具栏与 native WebContentsView 必须在任意 shell 缩放比例下保持同一页面边界。

已验证缺口

shell 缩放因子约为 1.095 时,renderer 发送 x=812.63, width=518.64 CSS px,主进程直接当作 DIP 使用。正确 native bounds 应约为 x=890, width=568。结果是网页覆盖左侧聊天 pane,并在右侧留下空白。

旧遮挡判断只要文档内存在任意 role=dialog 就隐藏每一个 native Web pane。底部 working directory、project 和 permission 等局部菜单即使完全位于聊天 pane,也会让相邻网页变为空白;同时 role=menu、role=listbox 和若干自定义全屏确认层没有进入同一规则。

浮层与多个 Web pane 的统一规则

浮层类型识别方式native Web 行为
局部 Popover、Dropdown、listbox、tab/split menurole=dialog/menu/listbox逐个 Web body 计算矩形;只隐藏实际相交的 pane。
全屏 modal、确认背景、附件预览data-native-view-occluder=true 或既有 merge backdrop全屏矩形与每个 Web body 相交,因此所有被覆盖 pane 隐藏。
tooltip、toast、drag cue、普通 portaled 内容不进入遮挡 selector不因短暂提示导致网页整体空白。
Desktop main/context/bookmark 原生菜单main process 独立 overlay owner沿用原生菜单生命周期,不由 renderer DOM 重复管理。

多 Web 分屏不共享一个全局 visible flag。每个 WebTabPane 使用自己的 body bounds 与同一组当前浮层分别计算;一个菜单只覆盖左侧 Web 时,右侧 Web 保持可见。Agent 画中画预览复用同一套 registerVisibleWebTabBounds / syncVisible 路径,只发布小窗 body 矩形,工具条按钮和右下角缩放柄留在 native view 之外。浮层关闭、移动或 resize 后由现有 MutationObserver、ResizeObserver 和 scroll/resize listener 重新发布 bounds。小窗拖动或调尺寸时 renderer 以 100ms 节流调用 syncVisible,指针抬起立即发布,避免每帧 IPC;全局 flush 仍是同一 tick 内的 microtask 合并。

设计

边界与排除

不强制重置用户缩放,不修改 split ratio、DOM 布局、preload API、站点缩放、Browser Agent、依赖或配置。Electron 的 WebContentsView.setBounds 接收 DIP,renderer DOM 测量属于 CSS px;renderer 保留测量精度,主进程负责单位转换和最终取整。

任务文件与验收

生产代码:apps/desktop/main.js、apps/web/components/center-tabs/web-tab-pane.tsx 和 apps/web/lib/browser/web-tab-bounds.ts。公开门禁:apps/desktop/scripts/check-webtab-zoom-bounds.js 及现有 web split 门禁。

实现证据

实现状态

单位转换、自动化门禁和已安装应用验收均已完成。