现象
装上 maid-atelier 皮肤后,在 Safari 里点击侧栏「设置」,面板不会出现。屏幕会变暗(蒙层正常出现),但面板本身看不见,观感像是界面卡住了。停用皮肤后一切正常,Chrome / Edge 等 Blink 内核浏览器也一直正常。
复现环境:macOS 26.6 + Safari 26.6,DSH 0.1.0-rc.6,dsh --profile web。在当前 main(873f5c6)上仍可复现。
根因
SettingsPanel 不是挂在 document 根上的 portal,它挂在侧边栏内容根节点内部,靠 position: fixed 浮出到视口。
而皮肤的侧边栏分层规则给这个节点加了 position: relative + z-index: 2:
body[data-dsh-maid-atelier] :is([data-pane='sidebar'], [class*='sidebarCol']) > div > :not(
[data-skin-chrome='sidebar-mascot'],
[data-skin-chrome='sidebar-corners'],
[role='tooltip']
) {
position: relative;
z-index: 2;
}
这两条合起来让该节点成为一个层叠上下文(stacking context)。Blink 允许 position: fixed 后代逃出祖先的层叠上下文,WebKit 不允许——面板因此被困在侧边栏那一层里,画不出来。
为什么现有的规则没能解决
maid-atelier.module.css 里已经有一条规则察觉到了面板位置特殊,在设置打开时把该节点提升到 z-index: 1000,注释也写明了「SettingsPanel is mounted inside that root instead of a document portal」。
但提升 z-index 只是抬高了这个层叠上下文本身,上下文依然存在,困在里面的 fixed 面板出不来。在 Blink 上本来就不需要它生效,所以这个缺口一直没暴露。
建议的修改
设置打开时让该节点退回 position: static; z-index: auto,即不再产生层叠上下文。面板自身的 z-index 随即在页面层级生效——这正是它在 Blink 上能盖住 sticky Markdown 横幅和会话头部的原因,行为不变。
body[data-dsh-maid-atelier][data-maid-settings-open]
:is([data-pane='sidebar'], [class*='sidebarCol'])
> div
> :has(
[data-slot='sidebar.settings']
> :is(button, [role='button'])[aria-expanded='true']
) {
- z-index: 1000;
+ position: static;
+ z-index: auto;
}
选择器不变,仍然只在 [data-maid-settings-open] 存在时匹配,设置面板关闭时零影响,侧边栏描金边框、Q 版娘、上下花边均不受影响。
排查记录(留给后来人)
这个 bug 会骗过几乎所有常规诊断手段,在 Safari 的 Web Inspector 里逐项测量,结果全是「正常」:
| 检查项 |
结果 |
getBoundingClientRect() |
800×401,尺寸与位置都正确 |
elementFromPoint() 打在面板中心 |
返回面板自己,「无遮挡」 |
| 面板自身计算样式 |
opacity: 1、visibility: visible、display: flex |
| 整条祖先链计算样式 |
无任何可使元素隐藏的属性 |
| 控制台 |
无报错(只有 sourcemap 404) |
几个当时看着很像、但实测都被排除的方向::has() 在 WebKit 失效、backdrop-filter 合成差异、侧边栏 overflow: hidden 裁剪、/api 同源围栏返回 403。
最终定位靠的是整体开关对照 + 二分:先确认「关掉皮肤全部样式表则面板正常」,再筛出与面板祖先链匹配的皮肤规则(约 11 条),逐条单独关闭,命中上述分层规则。
需要特别注意 elementFromPoint 的误导性:皮肤所有装饰层都带 pointer-events: none,命中测试会直接跳过它们,所以「点击测不到遮挡」不等于「视觉上没被遮挡」,这两件事在本例中必须分开看。
已验证
改动已基于当前 main(873f5c6)实现并验证:
- 全量测试通过(89 项,含新增的 1 项回归测试)
lib/client.js 已随源码重新构建,两次构建逐字节一致,产物中无绝对机器路径、无远程资源依赖
- 新增回归测试断言
position: static 与 z-index: auto 同时存在,并断言 z-index: 1000 不再出现,防止回退
- 同时更新了
keeps root-level relational selectors out of the skin scope 一例中写死旧值的断言
- Safari 26.6 实机验证:设置面板可正常打开,侧边栏各装饰层在面板开/关两种状态下均正常
现成分支在这里,如果合适我可以开 PR,或者你直接取用:
https://github.com/dingyi580/dsh-deep-whale/tree/fix/webkit-settings-dialog
现象
装上 maid-atelier 皮肤后,在 Safari 里点击侧栏「设置」,面板不会出现。屏幕会变暗(蒙层正常出现),但面板本身看不见,观感像是界面卡住了。停用皮肤后一切正常,Chrome / Edge 等 Blink 内核浏览器也一直正常。
复现环境:macOS 26.6 + Safari 26.6,DSH
0.1.0-rc.6,dsh --profile web。在当前main(873f5c6)上仍可复现。根因
SettingsPanel不是挂在 document 根上的 portal,它挂在侧边栏内容根节点内部,靠position: fixed浮出到视口。而皮肤的侧边栏分层规则给这个节点加了
position: relative+z-index: 2:这两条合起来让该节点成为一个层叠上下文(stacking context)。Blink 允许
position: fixed后代逃出祖先的层叠上下文,WebKit 不允许——面板因此被困在侧边栏那一层里,画不出来。为什么现有的规则没能解决
maid-atelier.module.css里已经有一条规则察觉到了面板位置特殊,在设置打开时把该节点提升到z-index: 1000,注释也写明了「SettingsPanel is mounted inside that root instead of a document portal」。但提升
z-index只是抬高了这个层叠上下文本身,上下文依然存在,困在里面的 fixed 面板出不来。在 Blink 上本来就不需要它生效,所以这个缺口一直没暴露。建议的修改
设置打开时让该节点退回
position: static; z-index: auto,即不再产生层叠上下文。面板自身的z-index随即在页面层级生效——这正是它在 Blink 上能盖住 sticky Markdown 横幅和会话头部的原因,行为不变。body[data-dsh-maid-atelier][data-maid-settings-open] :is([data-pane='sidebar'], [class*='sidebarCol']) > div > :has( [data-slot='sidebar.settings'] > :is(button, [role='button'])[aria-expanded='true'] ) { - z-index: 1000; + position: static; + z-index: auto; }选择器不变,仍然只在
[data-maid-settings-open]存在时匹配,设置面板关闭时零影响,侧边栏描金边框、Q 版娘、上下花边均不受影响。排查记录(留给后来人)
这个 bug 会骗过几乎所有常规诊断手段,在 Safari 的 Web Inspector 里逐项测量,结果全是「正常」:
getBoundingClientRect()elementFromPoint()打在面板中心opacity: 1、visibility: visible、display: flex几个当时看着很像、但实测都被排除的方向:
:has()在 WebKit 失效、backdrop-filter合成差异、侧边栏overflow: hidden裁剪、/api同源围栏返回 403。最终定位靠的是整体开关对照 + 二分:先确认「关掉皮肤全部样式表则面板正常」,再筛出与面板祖先链匹配的皮肤规则(约 11 条),逐条单独关闭,命中上述分层规则。
需要特别注意
elementFromPoint的误导性:皮肤所有装饰层都带pointer-events: none,命中测试会直接跳过它们,所以「点击测不到遮挡」不等于「视觉上没被遮挡」,这两件事在本例中必须分开看。已验证
改动已基于当前
main(873f5c6)实现并验证:lib/client.js已随源码重新构建,两次构建逐字节一致,产物中无绝对机器路径、无远程资源依赖position: static与z-index: auto同时存在,并断言z-index: 1000不再出现,防止回退keeps root-level relational selectors out of the skin scope一例中写死旧值的断言现成分支在这里,如果合适我可以开 PR,或者你直接取用:
https://github.com/dingyi580/dsh-deep-whale/tree/fix/webkit-settings-dialog