上一轮(v11)跑到 350 轮上限被中断,两个核心项写了但没生效。本轮只补没做完的部分,不重做已完成项。 已经确认 OK 的不要动:数字/单位分层(32px + 11px 灰 + 1.54px)、阴影 2 变体、1px 描边做进 shadow、46/46 单测、check.mjs 全绿。
src/styles/tokens.js 与各组件里写的是:
.b { font-size: 32px; line-height: 1; text-box: trim-both cap alphabetic; }
浏览器 computed style 实测结果:
font-size: 32px
line-height: 32px
text-box: "cap alphabetic" ← trim-both 被丢弃
getBoundingClientRect().height = 32.00px ← 行盒完全没压缩
探针:font-size:32px; line-height:1; display:inline-block
不带 text-box → height = 32.00px
带 text-box:trim-both cap alphabetic → height = 23.28px (-27.2%)
结论:这个 Chrome 版本支持 trimming,但不接受 text-box 简写里的 trim-both,必须改用两个独立长属性。
改成独立属性,两个都要写:
text-box-trim: trim-both;
text-box-edge: cap alphabetic;
如果 text-box-trim / text-box-edge 也拿不到效果,再试 text-box: trim-both cap alphabetic 配合 @supports (text-box-trim: trim-both) 兜底,但首选独立属性。
兜底方案(只有前两种都失败才用):用负 margin 或 padding-block 补偿补偿法,把行盒视觉高度压到 cap 高,但必须在代码注释里写明「浏览器不支持 trimming,用 margin 补偿」。
写一个 Node + Playwright 脚本 scripts/verify-textbox.mjs,自起 dev server,量三处:
.b 主数值(32px):输出 fontSize / lineHeight / computed text-box-trim / boxHeightboxHeight <= 26px(32px 字号 cap 高约 23.3px,留 2.7px 余量)boxHeight > 26px,脚本 exit 1 并在输出里指明失败项另外报表里给出:12px 正文、20px 小标题、32px 主数值 三档在加/不加 trim 前后的行盒高度对比表(这是本轮要向客户交代的核心数据)。
src/utils/type.js 里已经写好:
export const THIN = '\u2009'; // U+2009 THIN SPACE
export function mixCJK(s) { ... } // 汉字↔拉丁/数字两侧插 U+2009
但页面实测:
元素文本 "S4 机会验证评估 · 13 条"
字符码 83,52,32,26426,... ← 位置 2 是 32(普通空格 U+0020),不是 8201
全页 U+2009 计数 = 0
函数写了,没人调用。 必须接到实际渲染路径上。
找出所有渲染「中英混排字符串」的地方并接上 mixCJK()(或等价处理),至少覆盖:
S1 市场分析、S4 机会验证评估 · 13 条)A级、高证据、S3 机会点识别)近 7 天、人均 2.5 份)20260420 CX 复盘)6 小时前、40 小时)规则(严格):
20260420 内部不插)<code>、URL、文件名、纯英文串里插在 scripts/verify-textbox.mjs(或另起 verify-cjk.mjs)里:
textContent 的完整字符码数组,证明交界处是 8201[\u4e00-\u9fa5] [A-Za-z0-9] 命中数应为 0,或全部来自 <code>/URL 例外)现状:kf-spark 组件 4 个,全是同一种折线/柱状火花线。
补齐,每类都要有真实出现位置(不是造组件放着):
| 类型 | 用在哪 | 规格 |
|---|---|---|
| sparkline | 已有 4 处保留 | 宽 64-80px,高 20px,历史柱 opacity .35,最新 .95 |
| 进度环 / 进度条 | 机会卡评分(76/80/81.3 分)、阶段完成度、证据强度 | 环 直径 40-48px,描边 3px,数值居中;条 高 4px,圆角 2px |
| 对比条(条形对比) | 报告类型的份数分布(品类1/竞品25/ VOC10/痛点9/概念0)、成员产出对比 | 横向条,最大值占满,其余按比例;数字右对齐 |
| 热力小格 | 阶段 × 类型 的交叉分布、成员活跃度 | 格子 12-14px 方形,圆角 2px,4 档不透明度 |
铁律(来自调研,必须遵守):
aria-hidden="true",旁边配文字数字给读屏验收:截图 + 在页面实测每种图表的 DOM 数量(各 ≥ 1),并说明每种出现在哪个页面哪个位置。
统一成四档,不许出现第四种间距值:
卡内 padding 16px
卡内 gap 12px
卡片之间 24px ← 1.5×
区块之间 48px ← 3×
自查方法:把页面缩到 25% 截图,所有留白宽度一样 → 均匀呼吸(模板感);能看到明确的「块」在呼吸 → 对了。
写个脚本统计页面所有 margin/gap 的构成值种类,> 6 种就报警(排除 0、auto、百分比、负数)。
实测:该卡片里虚线占位框占近半张卡高,信息密度低。
要求:
align-items: start 而非 stretch).grid2 被 align-items:stretch 拉到 220px,内容只有 78px。全页面扫一遍,stretch 导致的空隙 > 24px 的都列出来并修掉| 场景 | 要求 | 禁止 |
|---|---|---|
| 数字变化 | 只滚变化位(1284→1301 只滚十位个位),500-750ms,cubic-bezier(.4,0,.2,1) |
从 0 滚到目标值(AI 味) |
| 卡片 hover | translateY(-1px),150ms |
scale(1.05) 放大 |
| 列表进场 | 400ms,错峰 40ms | 所有元素同时淡入 |
| 展开收起 | grid-template-rows: 0fr → 1fr |
max-height: 999px |
| 全局 | 只写具体属性 | transition: all |
| 无障碍 | @media (prefers-reduced-motion: reduce) 全部关掉 |
— |
验收:grep 证明 transition: all 0 命中、max-height:999px 0 命中、scale(1.0[0-9]) hover 0 命中;实测一个数字变化动画的 duration 值在 500-750ms 之间。
逐条对照现有代码,每条给出「命中/未命中 + 证据(文件:行号)」:
max-height:999px 展开动画transition: all#000 / #FFFbox-shadow 做凸起 / 凹陷(非克制的拟物)这一节的输出是本轮交付物的一部分,写在 docs/v11b-audit.md,逐条 1-15 编号。
| 页面 | 上限 | v11 现状 |
|---|---|---|
| 工作台 | 350 字 | 95(v10 口径,需按同口径复核) |
| 报告类型页 | 300 字 | 96 |
| 报告中心 | 200 字 | 38 |
口径统一:只统计可见文本节点的中文字符 + 中文标点,排除 SVG 内文本、aria-label、隐藏元素。脚本里写清算式,输出每个页面的数。
docs/v11b-report.md:
scripts/,可重复运行node scripts/check.mjs 与 node --test 'test/*.test.js' 必须全绿