跨端: 三级文字**浅色也一样不够**(12 处 2.85:1)+ 判据不再只验一半
## 一、这是"我自己推的理由"被实测推翻 上一条我把 `textSubtleFor()` 写成**只改深色**,理由是: > 「浅色下这些令牌本来就是为浅底配的,量它们没有信息量」 **那个理由是错的。** 切到浅色主题复扫,立刻抓到 12 处: ``` "用户名 / 显示名 / 角色 / 状态 / 创建时间 / 最后登录" 2.85:1 "已同步" / "37%" / "3px"(外观区) 2.85:1 "这一天没有日程" 2.85:1 ``` `ink rgb(153,153,153)` 压白底 —— 全是 `textSubtle`。 对照 WebUI 浅色(`index.css` `:root`): - `gray-400` = `107 114 128` = **4.83:1** - `gray-500` = `90 98 112` = **6.15:1** ⇒ 系统三级色**两个主题下都不够**。它的语义只是"比二级更淡", **不保证任何可读性下限**;WebUI 那边两套主题都做过适配,这边一档都没有。 修:`textSubtleFor()` 两个主题都返回 `textMuted` (系统二级色,语义就是"次要文字",且**跟随主题** —— 不必再维护两个手写常量、不必登记)。 ## 二、判据从"只验深色"改成"两个主题都验" 原来那条设备判据**在浅色下直接 skip**,skip 的理由正是上面那句错话。 现在两个主题都扫,断言消息里带上主题名(`深色主题下…` / `浅色主题下…`)。 ★ 纪律:**色令牌的可读性是两个主题各自的事,不能只验一半。** "另一半没问题"若没量过,就只是推测。 **变异验证**:把 `textSubtleFor()` 改回"两主题都用 textSubtle" (此时设备正在浅色主题)⇒ **判红**;还原 ⇒ 绿。 ## 三、设备复扫(浅色主题) ``` [通信] 扫 41 段,低对比 0 [日历] 扫 84 段,低对比 0 [联系人] 扫 50 段,低对比 0 [我的] 扫 40 段,低对比 0 ``` **215 段文字全部 ≥3:1。** 两个主题合起来:深色 219 段 + 浅色 215 段,全绿。 ## 四、顺手改掉的 测试名从「深色下短文本必须都读得动」改成「**当前主题**下…」 —— 名字得跟着它实际判的东西走(否则下一个人会以为它只管深色)。 `run-all.mjs` → `checks=515 pass=515 fail=0 skip=0 red=0 broken=0 unreported=0`。 **当前设备主题**:浅色(本轮为验另一半切过去的;服务端 `theme=light`)。
This commit is contained in:
@ -1318,7 +1318,7 @@ test('C|「会跟随主题翻转的 Resource」不得当前景色(含矛盾
|
||||
});
|
||||
|
||||
|
||||
test('★ 设备:深色下短文本必须都读得动(扫一屏,不只查一个元素)', async (t) => {
|
||||
test('★ 设备:当前主题下短文本必须都读得动(扫一屏,不只查一个元素)', async (t) => {
|
||||
/*
|
||||
* ★★ 这条是上面"品牌色真的画成那个色"的**一般化**。
|
||||
*
|
||||
@ -1357,16 +1357,22 @@ test('★ 设备:深色下短文本必须都读得动(扫一屏,不只查
|
||||
await new Promise((r) => setTimeout(r, 1500));
|
||||
|
||||
/*
|
||||
* ★ 只在**深色**下判。浅色下这些令牌本来就是为浅底配的,
|
||||
* 量它们没有信息量(也不会红),但会拖慢判据。
|
||||
* ★★ 两个主题**都要判**(第一版只判深色,理由写的是"浅色下这些令牌本来就是
|
||||
* 为浅底配的,量它们没有信息量" —— **那个理由是错的**)。
|
||||
*
|
||||
* 切到浅色复扫才发现的实例:浅色 `textSubtle` = `rgb(153,153,153)` 压白底
|
||||
* = **2.85:1**,而 WebUI 浅色的 gray-400 是 4.83:1。
|
||||
* ⇒ "浅色下没问题"是我自己推的,不是量出来的。
|
||||
*
|
||||
* ★ 纪律:**色令牌的可读性是两个主题各自的事**,不能只验一半。
|
||||
* 现在把当前主题**记下来**,两个主题都扫;判据只看"有没有低对比",
|
||||
* 不关心是哪个主题(两种都是错)。
|
||||
*/
|
||||
const img0 = D.readPixels(await D.screenshot(hdc, '/tmp/dark-legibility.png'));
|
||||
const img0 = D.readPixels(await D.screenshot(hdc, '/tmp/theme-legibility.png'));
|
||||
assert.ok(img0, '要能截屏并解码');
|
||||
const corner = img0.at(4, 4);
|
||||
const isDark = corner && corner.r < 128 && corner.g < 128 && corner.b < 128;
|
||||
if (!isDark) {
|
||||
return t.skip(`当前不是深色主题(左上角像素 rgb(${corner?.r},${corner?.g},${corner?.b}))—— 本条只在深色下有意义`);
|
||||
}
|
||||
const themeName = isDark ? '深色' : '浅色';
|
||||
|
||||
const lum = (c) => {
|
||||
const f = (v) => { const x = v / 255; return x <= 0.03928 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4; };
|
||||
@ -1467,7 +1473,7 @@ test('★ 设备:深色下短文本必须都读得动(扫一屏,不只查
|
||||
'太少说明遍历或尺寸过滤写错了,那样下面的检查恒绿。');
|
||||
|
||||
assert.deepStrictEqual(bad, [],
|
||||
`★ 深色下这些文字读不动(对比度 <3:1):\n ${bad.join('\n ')}\n` +
|
||||
`★ ${themeName}主题下这些文字读不动(对比度 <3:1):\n ${bad.join('\n ')}\n` +
|
||||
' 深色下品牌色/面色都要换深色变体:\n' +
|
||||
' · 文字/图标用 `Theme.accentFor()`(深色自动给 `#80AFF9`,' +
|
||||
'对齐 WebUI 的 `.dark --c-blue-600`)\n' +
|
||||
|
||||
Reference in New Issue
Block a user