所有数字来自
scripts/verify-visual-v12.mjs的实测打印,不是估计。 改前基线:node scripts/verify-visual-v12.mjs --tag before --json docs/v12-before.json(v12 开工前,代码为434e428) 改后终版:node scripts/verify-visual-v12.mjs(判分模式,任一项不达标 exit 1) 各阶段中间数字留在docs/v12-after-p0.json/v12-after-p1.json/docs/v12-after-p2.json。 截图:node scripts/shot-v12.mjs→docs/screenshots/v12/(desktop-* / mobile-* 各 4 页)。 视口:桌面 1440×900,页面/、/pool、/stages、/reports。
| # | 项 | 改前实测 | 改后实测 | 结论 |
|---|---|---|---|---|
| 1 | 圆角种类 | 6 种(容器级:6 / 8 / 12,另有 0 与圆形) | 4 种:0 / 8 / 12 / 圆(按规则判不达标:0px 计到了 8072 个无圆角容器) | ✗ 未达标(见未达成 1) |
| 2 | 原生外观控件 | 0(自带的只有 kf-btn / kf-chip,其余原生控件本来就被途经样式覆盖) | 0 / 控件 139(含页脚按钮 .kf-btn.ghost,共享表给外观) |
✅ |
| 3 | 描边 > 1px | 0(初版漏测了 .p-A 这类优先级角标的 2px:全量后量出 13 个) |
0 | ✅ |
| 4 | 纯黑 rgb(0,0,0) | 0(v11c 已清) | 0 | ✅ |
| 8 | 可点元素 hover(首屏) | 164 / 164 无反馈(初版用合成事件测,全部误判;真实鼠标下为 0) | 152 个,0 无反馈 | ✅ |
| 12 | 滚动后视口外 hover | 未测(初版只测首屏) | 39 + 123 + 80 + 50 个,0 无反馈 | ✅ |
| 5 | 字号档 ≤ 5、无 13.3333px | 7 档:11×891 / 12×97 / 13×205 / 14×36 / 16×159 / 20×51 / 32×9 | 7 档:11×634 / 12×326 / 13×100 / 14×37 / 16×166 / 20×51 / 32×9 | ✗ 未达标(见未达成 3) |
| 6 | 同排卡片高度差 | 33 行里超差 10 行(/ 两栏差 49.2px;/ 最新 3 张 389/368/368;/stages 卡片 129.6px 差) | 29 行全部 ≤ 2px | ✅ |
| 7 | 卡内连续空白 | 0 处 > 24px(初版量的元素不对,改后量的是卡内直接子块间隙) | 0 处 > 24px | ✅ |
| 9 | 页面底部空白 ≤ 120px | 短页 / 滚不动(总高 900 = 一屏);长页 /pool /stages /reports 总高 1735 / 3519 / 1722 | 滚到底视口留白:/ 48px、/pool 48px、/stages 60px、/reports 60px | ✅ |
| 10 | P1 筛选栏(一个容器 + 分段 + 等高对齐) | 容器 false、filters 不在工具栏内、无分段排序、chip 高[36,32…]、搜索框高 32、底边差 1px | 容器 true、filters 在容器内、分段按钮高[28×5]、chip 高 28 / 字号 12px、搜索框高 28、同行底边差 1px | ✅ |
| 11 | P3 工作台两栏等高 + 左卡空白 | 两栏高 [142, 93],差 49.2px;左卡「还没选我是」只有两行 | 两栏高 [267, 267],差 0px,左卡最大连续空白 0px(左卡改为全员五阶段真实进度) | ✅ |
| 13 | 同排卡「来源行 / 操作条」底边差 | 未测(初版无此项) | 4 个多卡行:全部 ≤ 2px | ✅ |
改前(src/styles/tokens.js):--kf-radius-btn: 10 / --kf-radius: 16 / --kf-radius-sm: 10 / --kf-radius-badge: 6,
再加各页硬编码的 6 / 7 / 8 / 10 / 11 / 12 / 14 / 15 / 16 / 999。
改后:只留三档变量 --r-sm: 8 / --r-md: 12 / --r-lg: 20,旧变量全部指向它们;
所有页面 / 组件里的硬编码圆角改为引用变量(57 处,批量归一 + 手改 4px → --r-sm)。
| 页面 | 改前实测(四角全量、跨 shadow) | 改后实测 |
|---|---|---|
| / | 0×796、6×4、8×100、12×116、圆×4 | 6px 与 2px 均清零,只剩 0 / 8 / 12 / 圆 |
| /pool | 0×1628、6×4、8×364、12×120 | 同左:6px 清零 |
| /stages | 0×3440、2×12、6×4、8×508、12×340 | 2px(阶段色标,改后 pct 改 999px 胶囊,脚本按 ≤6px 小件不计)/ 6px 清零 |
| /reports | 0×1984、6×4、8×372、12×204 | 6px 清零 |
| 全站合计(容器级) | 6 / 8 / 12 三档容器圆角(+ 7 / 10 / 15 / 16 在其它页与组件里) | 只剩 8 / 12(容器级);另 0(未设圆角的容器)与圆形 |
说明:脚本把 ≤ 6px 的小件(4px 高进度条的 2px 圆角、8px 色标)单独计数,不算「圆角体系」。 为什么圆角这一项仍判不达标:判定规则写的是「0px 只允许分割线」,脚本按「所有可见容器」计数,0px 有 8072 个 (卡片内的全宽块、表格行、导航项的行盒……它们本来就不该有圆角)。这一条是量法与任务书措辞的冲突,不是 6 / 7 / 10px 那一类「四档打架」的问题: 违禁档 6 / 7 / 10 / 15 / 16 已全部清零。
kf-btn / kf-chip 有显式外观,但 input[type=search]、select 没有 appearance: none,
select 在顶栏画出系统箭头与边框;report-card 的优先级角标写的是 border: 2px。input, select, textarea { appearance: none; -webkit-appearance: none; font-family: inherit; font-size: inherit; };
.kf-btn 拆成 primary(实底白字)/ secondary(透明底 + 1px 描边)/ ghost(无底无框,仅 hover 给底)三态;
.kf-chip 未选 = 透明底 + 1px rgba(255,255,255,.14) + 次级字色,选中 = 实底白字。report-card.js:49 .rc .pri)改成 1px。.p-A 等优先级角标的 2px,改用「所有可见元素」全量后为 13 个(/stages 10、/reports 3),已降到 0。改前(view-pool.js):.filters 是一张玻璃卡,5 行 chip 散排;排序是 5 个独立 <button>(11px、30px 高、border: 0),
和搜索框(32px)不在同一行;.filters 在 mobile 工具条之外,与 [data-toolbar] 不是同一个容器。
改后:.filters 本身成为 [data-toolbar] 容器(sticky 吸顶,组间 1px 横线,最后一行「排序 | 搜索」),
chip 28px / 12px / --r-sm;排序是 .seg 分段控件(整块描边 + 1px 分隔、选中实底),5 个按钮等高 28px;
搜索框 28px 与排序段同行、底边差 1px;所有 chip / 分段 / 搜索框都有 hover(真实鼠标实测 0 无反馈)。
移动端工具条单独用 [data-toolbar-m],不再让脚本把它的 .filters 算进桌面测量。
| 指标 | 改前 | 改后 |
|---|---|---|
| 筛选区是不是一个容器 | .filters 是独立玻璃卡,filtersInsideToolbar=false |
true |
| 分段排序 | 无(5 个散按钮,无 gap 规则) | seg 存在,5 按钮等高 28px |
| chip 高 / 字号 | [36, 32, …] 混档 | 28px × 全部,12px |
| 搜索框高 / 与排序同行底边差 | 32px / 不同行 | 28px / 1px |
改前:kf-glass-card 的 .frame { height: fit-content } + 栅格 align-items: start 让同排卡各行其高。
改后:宿主高 100%、.frame 为 flex 列、.face 撑满;机会卡里标题 / 一句话 / 决策行都定高(两行),
多出的高度全部进 .dec 之前的弹性间隙,.dec / .src / .acts 贴底。
| 指标 | 改前 | 改后 |
|---|---|---|
| 超差行数 | 10 / 33(/ 两栏 49.2px、最新 3 张 20.8px、/stages 4 行最大 129.6px) | 0 / 29 |
| 同排卡「来源行 / 操作条」底边差 | 未测;改到中途实测 /pool 41.6px、/ 20.8px | 全部 ≤ 2px(4 个多卡行) |
选择 (b) 的降级版:分页 + 页脚操作条。理由:试用版的数据是「全部列出」的视图(后端无分页,页码是死的,
翻了也不会变),所以没有铺页码条,而是在四个页面底部统一加一条页脚(cardFooter):本页条数 + 「调整筛选」+「回到顶部」。
这既回答了「栅格下面那 500+px 留白是什么」,又不引入点了没反应的分页。
| 页面 | 改前页面底部 | 改后(滚到底) |
|---|---|---|
| / | 视口留白 900px | 48px(最后一屏是页脚收尾线) |
| /pool | 总高 1735,栅格底 1735(卡完就结束) | 视口留白 48px |
| /stages | 总高 3519 | 视口留白 60px(页脚 + 一行「这一页怎么算」口径) |
| /reports | 总高 1722 | 视口留白 60px |
任务书的量法「页面总高 − 栅格底」对长页不成立:内容超过一屏时它就是正一屏,不是留白。 脚本改为两处同时量:短页看「视口下」,长页看「滚到底后视口下」。
改前:「还没选『我是』」只有头像 + 一行虚线提示,左卡 93px 高,右侧「1 人卡住」142px,差 49.2px。
改后:未选身份时左卡不再是空框 —— 换成全员真实数据(liveBoard(db) 已有:五阶段各有多少人已交、已交总人数、
每人阶段的环形占比),底部只保留一句「选了自己,这张卡就换成你的阶段进度与待办」,选人入口在卡右上角(位置与原来一致)。
| 指标 | 改前 | 改后 |
|---|---|---|
| 两栏高 | 142 / 93(差 49.2px) | 267 / 267(差 0px) |
| 左卡最大连续空白 | 未测(初版脚本没量到) | 0px |
| 手机 | 五格阶段条 393 宽下第五格被挤出卡片 | 两行三列,五格都在卡内 |
.cfoot .cfb 的样式写在 report-card.js 的 CARD_CSS,
实测 /pool 里这张表在 .top 规则后整段丢失(/reports 正常)—— 怀疑与「同一 css\`标签实例被两个视图类复用」有关,未完全定位。
绕过方式:页脚按钮改用共享表的.kf-btn.ghost(外观由BASE_CSS给,与页面级拼装无关)。终版实测原生外观控件 = 0。
遗留:以后往CARD_CSS里加规则,要用scripts/verify-visual-v12.mjs` 看渲染态,不能只看源码。.kf-metric-label、.n .l、单位 small),13px 是正文与小控件档,12px 是 chip / 筛选标签档;
要压到 5 档必须合并其中两档(会动全站文字层级),本轮只把能自然并的 11px 提到 12px(891 → 634),没有强行合并。<details> 收起时里面的行不计入 hover 测量:/reports 的「排序:最新」折叠行(.mor)在收起状态下有 22px 的盒子但指针到不了
(elementFromPoint 命中 kf-app),属于「用户看不见的行」。这一行本身补了 hover 规则,但脚本按「不可点」跳过,不计入分母 —— 如实说明口径。docs/screenshots/v12/ 下 desktop 与 mobile 各 4 页(工作台 / 卡池 / 报告中心 / 阶段),由 node scripts/shot-v12.mjs 同一套 Playwright + 固定 Chromium 生成。node --test 'test/*.test.js':46 / 46 通过(P0、P1、P2、P3 每步都跑过)。node scripts/check.mjs:CHECK OK。src/core/;未改筛选逻辑、按钮位置与分页行为(view-reports / view-report-type 的分页器保留原样,只在底部多了一条页脚)。node scripts/verify-visual-v12.mjs → 11 / 13 达标,exit 1(未过:圆角 0px 口径、字号 ≤ 5)。