## 症状
所有界面的「确认」类按钮看不见,但对应位置点击照样生效。
归档确认、删除、危险操作、状态徽标全部受影响;蓝色主按钮正常。
## 根因
`tailwind.config.js` 的 `colors` 里对 red/green/amber/orange/yellow
**同时写了两份定义**:先是固定 hex,紧接着又是 `accent('red')`。
JS 对象字面量重复键**后者胜出**,不报错、不警告 —— 读代码的人看到上面那份
hex 以为在用它,实际生效的是下面那份变量引用。
而 `index.css` 里当时只有 20 个变量(white / on-accent / gray / chrome),
没有任何 `--c-red-*`。CSS 里变量未定义会让**整条声明失效**:
.bg-red-600 { background-color: rgb(var(--c-red-600) / 1) } ← 整条被丢弃
于是 `bg-red-600` 退回透明,而 `text-white`(走 `--c-on-accent`,浅色下是纯白)
照常生效 → 白字落在白卡片上。按钮的盒子、padding、点击区域全都在。
实测部署产物里 32 个变量被引用但从未定义。blue 逃过一劫只因为它没有第二份
`accent('blue')` 定义,编译成了固定值。
## 修法(用户选 B:补齐变量,让强调色也参与主题)
`index.css` 新增 96 个变量,`tailwind.config.js` 去掉重复定义。
**强调色是两段语义色阶,深色下走向相反**:
- `50`–`300` = 表面(chip 底、提示条底、边框)→ 深色下**变暗**。
照搬浅色值的话 red-50 (#fef2f2) 在深色页面上是一块近白亮斑 ——
那是错误提示条的底,结果比正文还抢眼,上面的红字反而读不动。
- `400`–`900` = 前景(文字、图标)→ 深色下**变亮**。
照搬时 red-700 只有 2.67:1、amber-900 只有 1.90:1。现在每档 ≥4.5
(最低 red-400 = 5.93)。
**实心按钮底另立一组 `--s-*`,两种模式同值。**
那六档在深色下被提亮是为了 `text-red-600` 读得动,而 `bg-red-600 text-white`
的白字落在提亮后的浅红上只有 1.6:1。一个名字服务两种语义必然坏掉一头 ——
与此前 text-white/bg-white 那次同理。只覆盖 `backgroundColor`,
`text-*`/`border-*`/`ring-*` 仍走 `accent()`。
顺带把浅色 red-600 从官方的 220 38 38 压到 213 37 37:官方值落在 red-50 上
只有 4.41:1,而 `bg-red-50 text-red-600` 正是错误提示条。
## 防复发
`test/theme.test.mjs` 20 → 26 条,新增 6 条针对这次的:
- **Tailwind 实际使用的每个变量都在 index.css 有定义**。判据走 resolveConfig
而不是正则扫配置文本:出问题的变量名是 `accent('red')` 模板拼出来的,
源码里没有 `--c-red-600` 这个字面量,扫文本会漏掉正是要防的那一类
- colors 里没有重复的颜色名(这次 bug 的成因)
- 表面段深色下变暗 / 前景段在深色卡片上 ≥4.5:1(逐档断言,72 项)
- 实心底走 `--s-*` 且未被 `.dark` 覆盖
- 白字在实心底上 ≥3:1
新增 `test/manual/accent-verify.mjs`:真浏览器渲染 17 组配色 × 两模式,
读 `getComputedStyle` 量实际值,**把「背景透明」单独判为失败**(那正是本次
bug 的指纹)。只以 `hover:` 变体出现的档不能放进探针 —— Tailwind 不生成
未使用的基础类,探它必然透明,是假阳性。
## 验收
- theme.test.mjs 26 条全过;web 160 例;tsc 无错
- accent-verify 两模式各 17 项全过(浅色最低 4.51、深色最低 3.05)
- theme-verify 9 项全过;wide-regression 5 项全过
- 截图逐像素核对:浅色侧栏 (15,23,42) / 卡片 (255,255,255) / 页面底 (249,250,251);
深色 (12,14,18) / (24,27,33) / (17,19,24) —— 层次关系两模式一致
76 lines
3.6 KiB
Markdown
76 lines
3.6 KiB
Markdown
# 手工浏览器实测脚本
|
||
|
||
不进 `npm test` —— 它们需要一个跑着的 Chromium 与一个活的 Gateway。
|
||
日常回归靠 `../narrow-layout.test.mjs`(读源码验形态,无外部依赖)。
|
||
|
||
## 为什么两套都要
|
||
|
||
结构性断言守住「代码写成了什么形态」,量不出「按钮实际多大、点下去命中谁」。
|
||
|
||
窄屏那轮修复里最严重的一个 bug 是抽屉式侧栏(`fixed ... z-50` 铺满视口高度)
|
||
把底部导航最左那一项盖住 —— 按钮在那里、尺寸也够、`md:hidden` 之类的规则也
|
||
没写错,**只有 `elementFromPoint` 才能发现它命中的是抽屉里的 SVG**。
|
||
|
||
## 用法
|
||
|
||
```bash
|
||
# 窄屏:390px(iPhone 14 Pro)+ 320px(iPhone SE)
|
||
ADMIN_PW=<密码> npm run test:narrow
|
||
|
||
# 宽屏回归:窄屏修复不能把桌面改坏
|
||
ADMIN_PW=<密码> npm run test:wide
|
||
```
|
||
|
||
环境变量:
|
||
|
||
| 变量 | 默认 | 说明 |
|
||
|---|---|---|
|
||
| `ADMIN_PW` | 无(必填) | 管理员密码 |
|
||
| `ADMIN_USER` | `admin` | 登录用户名 |
|
||
| `AGENTMAIL_URL` | `https://mail.jianfgit.xyz` | 目标地址 |
|
||
| `CDP_URL` | `http://127.0.0.1:9222` | 浏览器 CDP 端点 |
|
||
| `PLAYWRIGHT` | `/usr/lib/node_modules/playwright/index.mjs` | playwright 入口 |
|
||
|
||
浏览器用的是本机 systemd 托管的共享 Chromium(`homeagent-browser.service`),
|
||
通过 CDP 连上去开自己的标签页,用完关掉。没有它时先
|
||
`systemctl start homeagent-browser`。
|
||
|
||
## 文件
|
||
|
||
| 文件 | 作用 |
|
||
|---|---|
|
||
| `narrow-probe-helper.mjs` | 连浏览器、登录、量盒子/溢出/命中区/命中测试 |
|
||
| `narrow-verify.mjs` | 窄屏 13 项验收 |
|
||
| `wide-regression.mjs` | 宽屏 5 项回归 |
|
||
| `inbox-group-verify.mjs` | 收件箱按会话分组 |
|
||
| `theme-verify.mjs` | 深浅两色的 WCAG 对比度 |
|
||
| `accent-verify.mjs` | 强调色(红/绿/橙/黄/蓝)17 组配色,两模式各一遍 |
|
||
|
||
`narrow-probe-helper.mjs` 里两个函数值得单独知道:
|
||
|
||
- `tapTargets(page, labels)` —— 量 `.tap` 按钮的**真实**命中区(`::after`
|
||
伪元素的尺寸)。`.tap` 刻意不改变视觉尺寸,所以只看 `boundingBox` 会误判成偏小
|
||
- `hitTest(page, selector)` —— 每个元素点下去是否命中自己。遮挡类 bug 只能这样查
|
||
|
||
`accent-verify.mjs` 存在的理由是一次真实事故:`tailwind.config.js` 的 `colors`
|
||
里同时写了固定 hex 与 `accent()` 两份 red/green/amber/orange/yellow,JS 对象
|
||
字面量重复键**后者胜出**(不报错),而 `index.css` 当时没有对应的 `--c-red-*`
|
||
变量。`rgb(var(--c-red-600) / 1)` 里变量未定义 → 整条 `background-color` 声明
|
||
失效 → `bg-red-600` 退回透明、`text-white` 的白字落在白卡片上:
|
||
**按钮看不见但点得动**。所有静态检查都过,只有肉眼能发现。
|
||
|
||
因此这个脚本量的是**实际计算值**:它把类名注入真页面、读 `getComputedStyle`,
|
||
把「背景透明」单独判为失败(那正是上述 bug 的指纹),再算 WCAG 对比度。
|
||
|
||
只以 `hover:` 变体出现的档(`bg-red-700` / `bg-blue-700`)**不能**放进探针:
|
||
Tailwind 不生成未被使用的基础类,探它必然得到透明背景 —— 那是假阳性。
|
||
它们由 `../theme.test.mjs` 的档位断言覆盖。
|
||
|
||
## 已知限制
|
||
|
||
headless Chromium 报告 `hover: none`,因此 `.reveal`(只在支持悬停的设备上隐藏)
|
||
在这里永远是可见的 —— 脚本只能验「触摸设备上可见」这一半,
|
||
「鼠标设备上隐藏」那一半靠 `../narrow-layout.test.mjs` 检查 CSS 规则存在。
|
||
|
||
没有像素级视觉比对:字体差异下极脆,维护成本高于收益。
|