内置浏览器原生页面边界
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 menu | role=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 合并。
设计
- renderer 继续发送
getBoundingClientRect()得到的 CSS px。 - 主进程只在 renderer IPC 边界读取
event.sender.getZoomFactor(),把 CSS px 转为 native DIP,再执行现有整数化和非负尺寸约束。 sync-visible与兼容入口set-bounds使用同一转换;主进程内部已经是 DIP 的 show/hide/transfer 路径不重复缩放。- shell 缩放变化会触发现有 renderer
resizelistener,重新测量并发送当前 bounds;主进程在每次 IPC 上读取当前缩放因子。 - 无效或非正缩放因子按
1处理。 - DOM 浮层只在其可见矩形与当前 Web body 相交时遮挡 native
WebContentsView。位于聊天 pane 内的 working directory、project、permission 等菜单不得隐藏相邻分屏中的网页;覆盖网页区域的对话框、附件预览和 merge backdrop 仍需隐藏 native view,关闭后由现有 bounds observer 恢复。
边界与排除
不强制重置用户缩放,不修改 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 门禁。
- 自动化覆盖 100% 缩放、约 109.5% 缩放、无效缩放因子、两个 IPC 入口和现有 desktop 回归。
- 安装版使用默认 18100 worker;在非 100% shell 缩放下验证 DOM body 与 native viewport 同宽同高,并检查分屏、split ratio 调整及窗口缩放。
- 视觉验收只使用一张当前 viewport 截图;不启用 OCR、候选框或多轮 crop。
- 公开回归必须覆盖:左侧 working directory/project menu 与右侧 Web body 不相交时保持可见;menu/listbox 与单个 Web body 相交时只隐藏该 pane;全屏 modal backdrop 隐藏所有相交 pane;只有边缘接触而没有面积重叠时保持可见。
实现证据
- desktop 与 web 完整检查通过,动态 renderer 测试保留 DOMRect 小数并验证
syncVisiblepayload。 check:web-split执行矩形相交回归:左侧 working directory/project menu 不隐藏右侧 WebTab;dialog/menu/listbox、相交浮层与全屏 dialog backdrop 按每个 Web body 分别判断;零面积和仅边缘接触不隐藏。通用DialogOverlay、权限确认、context click-catcher 和 scoped drop overlay 通过data-native-view-occluder进入同一判断。- 最终规格复核与质量复核均为
PASS;未修改产品 CSS、现有菜单尺寸、位置、圆角或交互结构。 - 安装版在约 109.5% shell 缩放下,DOM body 换算结果与 native viewport 均为
568×763 DIP。 - 窗口调整为
1350×800后,DOM body 换算结果与 native viewport 均为526×712 DIP;恢复窗口后仍一致。 - 默认 18100 worker 健康检查通过,CDP 9223 同时观察 shell 与当前 Bilibili 原生页面。
实现状态
单位转换、自动化门禁和已安装应用验收均已完成。