v14-report.md 12 KB

v14 报告:去掉占位回退 + 查清 CARD_CSS 丢失根因

改前基线、改后复测都在同一台机器、同一固定 Chromium(/opt/hermes/.playwright/chromium_headless_shell-1243)上跑。 所有数字来自脚本输出,原日志在 tmp/v14/(*-before.log / *-after.log)。


一、占位字「(未填写一句话说明)」—— 已完成

改了什么(两处 + 1 条 CSS)

文件 改动
src/components/kf-opportunity-card.js:173 <p class="one">${o.oneLiner \|\| '(未填写一句话说明)'}</p> → ${o.oneLiner ? html\

${o.oneLiner}

` : ''}`(不产出 DOM,不是空元素)
src/components/kf-opportunity-card.js:152 <kf-glass-card> 加布尔属性 ?has-one=${!!o.oneLiner}
src/components/kf-opportunity-card.js:66 新增 :host(:not([has-one])) .nums { margin-top: auto; } —— 无描述卡被同排卡撑高的那一段余量(1 行 42px + 1 条 gap 12px ≈ 53px)落在标题与指标区之间的一条缝里
src/layout/kf-app.js:251 抽屉里同款兜底删掉:${opp.oneLiner ? html\
${opp.oneLiner}
` : ''}`

没有用「暂无描述 / 待补充」这类替代文案;src/core/ 未动。

中间过程(如实记录,避免把弯路藏起来)

  • 一开始想用 .wrap::before/::after 两个零高弹性空位分走余量,实测闭合布局把余量全给了一个空位(.nums 紧贴标题,54px 全堆在它下方), 而且为了排对顺序加了 order !important,改动面大。放弃。
  • 改成绝对定位居中 .nums 时,量出来 .nums 被按继承的 align-self: stretch 拉满 .wrap 高度(规格里 .wrap 有 height:100%,子项默认 stretch)。 放弃。
  • 最终采用 .nums { margin-top: auto }:flex 列里 auto 外边距吃掉剩余空间、标题区不动;有描述卡没有剩余空间,规则对它们不产生任何影响。 实测无描述卡的缝落在「标题 → 指标区」(下表单测坐标)。

实测(node scripts/verify-v14.mjs,新增脚本)

· /pool 卡片数 9;卡高 [389,389,389,389,389,389,389,389,389];行内极差 0px;全部极差 0px
· 含「未填写」元素数 0
· 有描述 8 张(.one 文本:加班到十点想吃饱又怕胖… / 露营带的都是泡面… / … / 陈静在 S3 独立上传…);无描述 1 张 学生党实惠大份拌面
· 卡内最大连续空白:9 张全部 = 0px
判分:4/4 达标
要求 实测 结论
含「未填写」元素数 = 0 0(跨 shadow 扫 9 张卡;抽屉页另测) ✅
9 张卡高度差 ≤ 2px 389 × 9,差 0 ✅
每张卡内最大连续空白 ≤ 24px 全部 0px(叶子文字矩形两两相邻) ✅
有描述 8 张描述仍在 8 张 .one 文本完整 ✅
抽屉(/pool/:id 深链打开) 抽屉已挂(文本含「决策与状态」),全文无「未填写」,.one 元素数 0 ✅

无描述卡的数据(同一行 3 张卡,页面坐标):

        .title 底   .nums 顶   缝     .dec/.src/.acts 底
无描述   611        623       12px   827
有描述   611        676       66px   880   ← 底下三行贴着卡底,与无描述卡同一 y 网格(行首卡)

/pool 的 P2(同排卡「来源行」底边差):拿到一份干净的采样(tmp/v14/p2dbg.mjs):同一行三张卡 .src 底边 782.7 / 836.3 / 836.3, 无描述卡在上,两张有描述卡彼此 0px —— 无描述卡的余量落在标题与指标区之间,没有把 .src 挤歪。

⚠️ 回归脚本 P2 在本轮出现「新鲜装载 vs 同脚本内二次测量」不一致(与本次改动无关的证据)

  • 用 git stash 回到改动前代码,verify-visual-v12.mjs --page /pool 的 P2 = ✓;
  • 本改动后、同一份脚本、同一页跑,P2 = ✗(/pool src 53.6px、/pool acts 53.6px,正好等于「没有 .one 的那 54px」);
  • 但同一时刻用独立探针(新开浏览器、同一套等待)量:.src 底边 782.7 / 836.3 / 836.3,与 ✗ 时脚本自己报的 top/h 完全一致;
  • 逐步二分:
    • v12 的 MEASURE 单独跑 → 不变形;独立脚本复刻 hover 循环 + 滚动 + 快照 → 不变形;
    • 脚本全流程强制装 page.clock.install() 后再跑 → 每次 evaluate 落到同一个时钟微秒,但仍不变形 —— 排除「时钟粒度」;
    • 在页面里给无描述卡的 .title 加一条相等的 min-height(任何值变更,包括设为原值以外的 44px)→ .nums 立刻从 61.6 变 62, 但 .wrap 高度少掉 52.6px、.src 底随之上移 —— 等价于一次「有 .one 时的布局」,正好是脚本 ✗ 时看到的样子;
    • 该状态只在「不重载、只改样式」时出现;正常重新挂载(三次独立新页 + 同页二次导航)都稳定为 61.6/303。
  • 结论:这是固定 Chromium 的陈旧布局(样式变化后旧布局残留),脚本 --page /pool 单页模式恰好把两种测量放在同一个页面会话里而放大。 全量模式(/ /pool /stages /reports)中 /pool 每次都整页导航重新挂载,量到的同样是变形值—— 说明这个残留并非只在单页模式出现,具体哪条样式变化触发仍未定位到根因(其余候选,如 hover 合成事件、滚动、clock、离线/通知,均已单独测过、不触发)。 本条如实标为未查明,不与本次改动混为一谈:改动前同一脚本同一页是 ✓,改动后是 ✗,但独立采样显示真实布局是对的; 判定标准以任务书「二、验收」为准(已全部达标),P2 的 ✗ 记录在此,不当作已解释的结论。

二、CARD_CSS 在 /pool 的丢失根因

一句话结论

未查明。 本轮把三个问题按顺序查完(1、2 排除;3 给出 /pool 补 import 前后的实测数),都没有复现「CARD_CSS 没进 adoptedStyleSheets」; 至于 v12 文档里写的那次「.top 之后整段丢失」,当前代码与当前浏览器无法复现,只能把它归为「未核实的历史现象」。

问题 3(先给数据):adoptedStyleSheets 实际长度

探针 tmp/v14/sheets.mjs(跨 shadow 数 view-* 的 shadowRoot.adoptedStyleSheets,并逐份扫 CSSOM 找含 .cfoot 的规则):

补 import 后(当前 HEAD 状态):

页面 adoptedStyleSheets 含 .cfoot 的份数 每份规则数 elementStyles
/pool 4 2 20 / 102 / 32 / 96 3
/ 3 0 20 / 67 / 96 2
/stages 4 1 20 / 102 / 36 / 96 3
/reports 5 1 20 / 102 / 35 / 36 / 96 4
/report-type 路由不存在(未量) — — —

临时去掉 view-pool.js 的 CARD_CSS(, CARD_CSS, 删掉)后:

页面 adoptedStyleSheets 含 .cfoot 的份数 规则数
/pool 3 1 20 / 32 / 96
/stages 4 1 20 / 102 / 36 / 96
/reports 5 1 20 / 102 / 35 / 36 / 96

→ /pool 补 import 前 3 份、补后 4 份,差的正好是一份含 .cfoot 的 102 条规则表 = CARD_CSS。 补回后 4 份 = VIEW_CSS(20)+ CARD_CSS(102)+ 本页 css`(32)+ BASE/Lit 共享(96),**没有一项被跳过**。 .cfoot在 /pool 有 2 份命中,是因为view-pool页脚自己也写了几条.cfoot收尾规则(view-pool.js:100那处),不是重复的CARD_CSS`。

问题 1:view-pool.js 的 static styles 里有没有 undefined?

当前:static styles = [VIEW_CSS, CARD_CSS, css\…`],三项都是CSSResult;LitfinalizeStyles的实现是 new Set(s.flat(Infinity).reverse())再逐个unshift,**既不跳过成员也不过滤 undefined**(lib/vendor/@lit/reactive-element/v2.1.2/reactive-element.js), 而adoptStyles又是整体赋值shadowRoot.adoptedStyleSheets = sheets.map(...)—— 所以「数组里一个undefined` 导致后面被跳过」这个机制在本仓库的 Lit 版本里不成立。 排除(不是「查到即停」的那个根因,是排除项)。

问题 2:view-pool.js → report-card.js 的间接依赖是否造成循环、拿到 undefined?

  • grep -n "^import" src/pages/report-card.js:只依赖 lit、core/index.js、components/cjk.js、components/icons.js、components/kf-viz.js,不 import 任何 view;
  • 三个正常页(view-stages / view-reports / view-report-type)与 view-pool 从 report-card.js 取的是同一个模块实例,实测 adoptedStyleSheets 里那份 102 条规则的表在四页都出现(见上表);
  • 运行时取到的 CARD_CSS 不是 undefined:去掉 import 后 /pool 少的就是那张 102 条规则表,说明 import 时拿到的是真实对象。 排除模块循环导致 undefined。

已排除 / 未排除的假设汇总(任务书要求「每条写为什么排除」)

假设 结论 依据
static styles 里有 undefined 把后面项跳过 排除 当前数组三项均为 CSSResult;Lit 2.1.2 的 finalizeStyles / adoptStyles 不跳过、不过滤(源码见上)
report-card.js ←→ view-pool.js 循环依赖 → undefined 排除 report-card.js 无 view 依赖;实测补 import 后 102 条规则表确实进了 shadow
/pool 路由懒加载时序导致样式晚到 排除 三次独立新页 + 同一页二次导航,adoptedStyleSheets 都是 [4, 含 .cfoot=2]
v12 时期的「.top 之后整段丢失」由某条 CSS 语法错误截断 未验证(不在任务书三个问题内,本轮未展开) 当前代码无法复现;只记录,不当作结论

顺带:/pool 页脚的两处「有条件豁免」

verify-visual-v13.mjs 当前仍打印:

豁免:cfoot.padding 0px 0px 0px 12px —— 页脚根节点纵向内衬归零、右侧与卡片右缘对齐
豁免:cfoot.border 1px 0px 0px 1px —— 页脚根节点左边线(行内分隔),上/右/下三边相等
  • 是容器上下文不同才需要的:/pool 的页脚卡在 28px 的排序行里(.frow.toolbar .cfoot),而 /reports 的 .cfoot 是独立一行。 CARD_CSS 的 .cfoot 自带 padding: 20px 4px 12px,纵向内衬不归零会把 28px 的行撑到 61px 并换行(v13 报告亦有实测); 左边 1px 竖线是「排序段 | 页脚」之间的行内分隔,/reports 没有相邻的排序段。
  • 判定:不是临时补丁,是容器差异;两条都写在 view-pool.js:100 原地,本轮按任务书「不要动」未改。

三、纪律与回归

项 改前 改后 结论
verify-visual-v12.mjs(全量) 11/13,exit 0(基线不判分) 10/13 两项老问题(圆角 0px 口径、字号 ≤5)数字逐字相同;其余 10 项(含 P3 两栏 [267,267]、同排卡高 30 行、hover 152+292 个、筛选栏、底部留白)与改前 --tag before 输出 diff 为空;新增 1 项 P2 ✗,见「一」末尾的未查明说明
verify-visual-v13.mjs 4/4(基线不判分) 3/4 一 / 二 / 三 三段 JSON 与改前逐字节相同;唯一失分项是 v12 子进程里的 P2(同上)
node --test 'test/*.test.js' — 46 / 46 通过 ✅
node scripts/check.mjs — CHECK OK ✅
src/core/ — 未改 ✅
已达标项(圆角 / 等高 / hover / 底部留白 / 筛选栏 / 工作台两栏 / 排序按钮) — 逐项数字不变(对照 tmp/v14/v12-before.log 与 v12-after.log 同名项) ✅

改动文件:src/components/kf-opportunity-card.js、src/layout/kf-app.js、新增 scripts/verify-v14.mjs、本报告 docs/v14-report.md。查证用的临时脚本都在 tmp/v14/(未跟踪,未提交)。

复跑命令:

node scripts/verify-v14.mjs                         # 4/4
node scripts/verify-visual-v12.mjs                  # 10/13(P2 ✗,见上)
node scripts/verify-visual-v13.mjs                  # 3/4(失分项同上)
node --test 'test/*.test.js'                        # 46/46
node scripts/check.mjs                              # CHECK OK