fix: 窄屏实测修复 —— 删抽屉、44px 命中区、触摸设备可见的次要动作

用 playwright 连本机共享 Chromium,在 390px(iPhone 14 Pro)与 320px
(iPhone SE)量真实盒子。之前的窄屏适配是「照着规则写对」,实测发现
一个功能性 bug 加五处可用性问题。

## 抽屉式侧栏遮挡底部导航(真 bug)

抽屉是 `fixed left-0 top-0 bottom-0 z-50`,铺满整个视口高度;底部导航没有
z-index。抽屉打开时点最左那一项「收件」,elementFromPoint 命中的是抽屉里的
SVG,不是导航按钮 —— 按钮在那里、尺寸也够、CSS 规则也没写错,只有命中测试
才能发现。

**删掉抽屉而不是给导航加 z-index**:抽屉装的六项(收件/发件/联系/用户/新建/
管理)与底部导航完全重复,唯一独有的是退出登录。为一个按钮维护一套 fixed
层级加遮罩不划算,而它还附带「Esc 关不掉」「底层未锁滚」两个毛病。

退出登录移到「我的」页 —— 它与密码、密钥同属「账号自身」,而那页此前根本
没有退出入口。`NavToggle` 与 uiStore 的 navOpen/toggleNav/closeNav 一并删除。

## 触摸命中区:新增 .tap

详情页那排工具按钮视觉高度只有 15-16px(实测「标记已读」48x16、「对话树」
54x16、「转发」42x16、「抄送」20x15),移动端下限是 44x44。

直接加 padding 会把本来就挤的头部撑散、320px 下换行,因此用居中的透明伪元素
扩大命中区:**视觉一像素不动**。只在 max-width:767px 生效 —— 桌面用鼠标精度
足够,而扩大后的命中区在密排工具栏里会互相重叠,点一个可能命中隔壁那个。

覆盖 MailView / ContactPanel / WorkCard / ModelScopePanel / AdminUsersPage /
ComposePage / ThreadView / KeyPanel / QuotaPanel / Attachments / BackButton。

## 看不见却按得动的按钮:新增 .reveal

`opacity-0 group-hover:opacity-100` 在没有 hover 的设备上永远是 opacity:0,
**但仍然接收点击** —— 实测联系人列表里 elementFromPoint 命中的就是那个看不见的
「归档」。一个看不见却按得动的破坏性按钮比没有按钮更糟:人以为点的是卡片,
实际归档了一条会话。

改为默认可见,只在 `(hover: hover) and (pointer: fine)` 时隐藏。
单看 hover 会把带触摸板的平板算进去。

## 对话树

- 缩进随屏宽自适应:固定「每级 20px、上限 8 级」= 最多 160px,320px 屏还要
  去掉 px-4 的 32px 与连接线 18px,卡片只剩 110px,发件人一行直接被 truncate
  吃掉。窄屏改为每级 10px、上限 5 级
- 补返回出口:原先只有「关闭」。两者语义不同 —— 返回退出整个详情栏回到列表,
  关闭只收起树、留在这封邮件上

## 把实测脚本留进仓库

`web/test/manual/`(`npm run test:narrow` / `test:wide`),不进 npm test ——
要一个跑着的浏览器加一个活的 Gateway。

留着而不是用完即删,是因为结构性断言守不住「按钮实际多大、点下去命中谁」,
而这次最严重的 bug 恰好只有 elementFromPoint 能发现。helper 里两个函数专门
为此:tapTargets() 量 .tap 的真实命中区(伪元素尺寸,不是 boundingBox),
hitTest() 验每个元素点下去是否命中自己。

## 验证

- 窄屏 13 项 + 宽屏 5 项全通过。宽屏回归特意验了两件只该在窄屏生效的事:
  .tap 伪元素 content 为 none、没有返回按钮
- narrow-layout.test.mjs 从 20 条扩到 28 条,逐条钉住上面每个修复
- 无横向溢出:390px 与 320px 下 scrollWidth === clientWidth
- 生产已部署
This commit is contained in:
2026-09-02 23:53:59 +08:00
parent 9e5c557cdf
commit 342282b92c
26 changed files with 759 additions and 134 deletions

View File

@ -105,8 +105,65 @@ SSE 连接的 handler 在首次连接时从缓冲区头部开始(客户端传
**修法**同上sessionrate.go 重写为调用 RateLimitCheckAndRecord
### P2 — 组件级测试
**现状**前端无任何组件测试前端回归只靠 lint 与构建
**现状**有结构性回归`web/test/narrow-layout.test.mjs`28 条断言
读源码验形态与一套 playwright 手工脚本**没有渲染组件跑断言的测试**。
**范围**关键组件AddressInput 补全PermissionPanel 决策WorkCard 预算渲染)。
**已有的浏览器实测**`web/test/manual/``npm run test:narrow` /
`npm run test:wide`)—— 连本机共享 Chromium 量真实盒子与命中区
不在 `npm test` 因为要一个跑着的浏览器加一个活的 Gateway
剩下的是把它接进 CI需要一个 headless 环境与一个测试用 Gateway 实例)。
### 窄屏实测修复2026-09-02
playwright 连本机共享 Chromium 390pxiPhone 14 Pro 320pxiPhone SE
两档实测。**一个功能性 bug 加五处可用性问题**
**抽屉式侧栏遮挡底部导航(真 bug已删抽屉**
抽屉是 `fixed left-0 top-0 bottom-0 z-50`铺满整个视口高度底部导航没有
z-index抽屉打开时点最左那一项收件」,`elementFromPoint` 命中的是抽屉里的
SVG不是导航按钮
修法是**删掉抽屉**而不是给导航加 z-index抽屉里六项收件/发件/联系/用户/
新建/管理与底部导航完全重复唯一独有的是退出登录为一个按钮维护一套
fixed 层级 + 遮罩不划算何况它还引入了遮挡Esc 关不掉底层未锁滚三个问题
退出登录移到我的 —— 它与密码密钥同属账号自身」,而那里此前根本
没有退出入口
**触摸命中区(新增 `.tap`**
详情页那排工具按钮视觉高度只有 15-16px实测标记已读48x16、「对话树
54x16、「转发42x16、「抄送20x15移动端下限是 44x44
直接加 padding 会把本来就挤的头部撑散 320px 上换行因此改用居中的透明
伪元素扩大命中区**视觉一像素不动**。只在 `max-width: 767px` 生效 ——
桌面用鼠标精度足够而扩大后的命中区在密排工具栏里会互相重叠
覆盖 MailView / ContactPanel / WorkCard / ModelScopePanel / AdminUsersPage /
ComposePage / ThreadView / KeyPanel / QuotaPanel / Attachments / BackButton
**悬停才显形的按钮在触摸设备上永远透明却按得动(新增 `.reveal`**
`opacity-0 group-hover:opacity-100` 在没有 hover 的设备上永远是 `opacity: 0`
但仍然接收点击 —— 实测联系人列表里 `elementFromPoint` 命中的就是那个看不见的
归档」。一个看不见却按得动的破坏性按钮比没有按钮更糟人以为点的是卡片
实际归档了一条会话
改为默认可见只在 `(hover: hover) and (pointer: fine)` 时隐藏 ——
单看 `hover` 会把带触摸板的平板算进去
**对话树缩进在 320px 下把卡片压成竖条**
固定每级 20px上限 8 」= 最多 160px320px 屏还要去掉 `px-4` 32px
连接线 18px卡片只剩 110px发件人一行直接被 truncate 吃掉
窄屏改成每级 10px上限 5
**对话树窄屏没有返回出口**
只有关闭」。两者语义不同返回退出整个详情栏回到列表关闭只收起树
留在这封邮件上补了 `BackButton`
#### 验证
playwright 端到端 13 项全通过底部导航六项都命中自己」、
工具按钮命中区 >= 44px」、四个页面无横向溢出、320px 无横向溢出);
宽屏回归 5 项全通过(三栏并排、常驻侧栏仍有退出登录、无返回按钮、
`.tap` 伪元素在宽屏不生效、无溢出)。
`web/test/narrow-layout.test.mjs` 从 20 条扩到 28 条,把上述每一条都钉住。
### P2 — 深色主题
**现状**:只有浅色主题,深夜使用刺眼。