fix(opensource): 修视觉终审的四个 P1 与灰阶/对齐细节

视觉终审对开源页改版判「需修」,逐条修完并量化复验。

P1-1 数据板空档与三段右缘不齐:streak 只占半栏、snake 通栏 → 右侧空 306px。
- 网格改 `repeat(auto-fit, minmax(320px, 1fr))`,仅一张非通栏卡时加 `.pf-card-solo`
  (`grid-column: 1/-1`),语言条去掉 max-width
- 实测:统计行/语言条/数据板右缘统一 959px,streak 卡宽 298→638

P1-2 卡内 SVG 文字不可读:streak 固有 495px 被压到 298px(0.6×),14px 标签变 8.4px。
- 卡改全宽后 1:1 渲染(实测 rendered=495=natural);抓取参数把次级灰换成站点 ink:
  亮色 #3f424a(10.05:1)、暗色 #b9bec8(9.07:1),旧值 #9aa0aa 仅 2.63:1

P1-3 移动端打字机折行推挤:390 下第 4 句 260px > 可用 230px 必折两行,
min-height:1.6em 挡不住 → 每轮下推 21px 再弹回。
- `@media(max-width:560px){.typing{min-height:calc(1.6em*2)}}`(实测 42px 恒定零推挤)
- 光标收成 2px 竖条 + baseline 对齐(原来是 0.5em 实心块,两行时被拉到行间)
- typing 第 4 句裁短(中文 ≤16 字、英文 ≤36 字符)

P1-4 streak 卡入场动画空壳帧:SVG 内 fadein 序列(环 0.4s/数字 0.6s/…/1.2s)+ lazy
加载 → 用户先看到 0.5–1.5s 半成品,截图也会随机拍到空卡。
- 抓取脚本新增 freezeAnimations():剥掉全部 animation 声明、opacity:0 改 1、
  删除 @keyframes;重抓后 grep animation:/opacity: 0 均为 0(streak 各 6KB、
  snake 35KB→20KB)

P2 一并:
- streak 亮色容器 grayscale(1) 回到灰阶基调;暗色蛇卡改 grayscale+invert+contrast+
  brightness 组合,空网格不再与底色同色
- 项目墙描述 text-wrap: pretty(长描述末行孤词)
- 统计口径注释改为「三格」,不硬塞第 4 格(贡献数已由热力图承载)
- 社交图标行负 margin 做光学对齐

附:content-lint 增加 SKIP_ALL 白名单(一次性预览路由 /books-preview/ 无 en 对应页,
语言切换链接会误报断链+配对缺)

验证: 构建 51 页 exit 0;content-lint 54 页 0/0/0;E2E 46/46;
      Playwright 实测三段右缘 959 一致、streak 1:1、1280/390 零横向溢出、
      移动打字机高度 42px 恒定、光标 2px、项目墙 text-wrap=pretty

Spec: 2026-11-02_blog-5i-fonts-polish (T8 修复)

Co-authored-by: GLM-5.3
This commit is contained in:
wait4xandGLM-5.3 committed 2026-11-03 11:48:25 +08:00
1 parent 907f64472a
commit cfe508ff14
10 files changed
+96 -62

No files matched your search

+1 -1
View File
@@ -1 +1 @@
<svg viewBox="-16 -32 880 192" width="880" height="192" xmlns="http://www.w3.org/2000/svg"><desc>Generated with https://github.com/Platane/snk</desc><style>:root{--cb:#1b1f230a;--cs:purple;--ce:#ebedf0;--c0:#ebedf0;--c1:#9be9a8;--c2:#40c463;--c3:#30a14e;--c4:#216e39}.c{shape-rendering:geometricPrecision;fill:var(--ce);stroke-width:1px;stroke:var(--cb);animation:none 35300ms linear infinite;width:12px;height:12px}@keyframes c0{4.52%{fill:var(--c1)}4.54%,100%{fill:var(--ce)}}.c.c0{fill:var(--c1);animation-name:c0}@keyframes c1{66.85%{fill:var(--c2)}66.87%,100%{fill:var(--ce)}}.c.c1{fill:var(--c2);animation-name:c1}@keyframes c2{3.67%{fill:var(--c1)}3.69%,100%{fill:var(--ce)}}.c.c2{fill:var(--c1);animation-name:c2}@keyframes c3{1.97%{fill:var(--c1)}1.99%,100%{fill:var(--ce)}}.c.c3{fill:var(--c1);animation-name:c3}@keyframes c4{2.82%{fill:var(--c1)}2.84%,100%{fill:var(--ce)}}.c.c4{fill:var(--c1);animation-name:c4}@keyframes c5{3.39%{fill:var(--c1)}3.41%,100%{fill:var(--ce)}}.c.c5{fill:var(--c1);animation-name:c5}@keyframes c6{2.26%{fill:var(--c1)}2.28%,100%{fill:var(--ce)}}.c.c6{fill:var(--c1);animation-name:c6}@keyframes c7{10.19%{fill:var(--c1)}10.21%,100%{fill:var(--ce)}}.c.c7{fill:var(--c1);animation-name:c7}@keyframes c8{9.06%{fill:var(--c1)}9.08%,100%{fill:var(--ce)}}.c.c8{fill:var(--c1);animation-name:c8}@keyframes c9{41.63%{fill:var(--c1)}41.65%,100%{fill:var(--ce)}}.c.c9{fill:var(--c1);animation-name:c9}@keyframes ca{12.74%{fill:var(--c1)}12.76%,100%{fill:var(--ce)}}.c.ca{fill:var(--c1);animation-name:ca}@keyframes cb{13.59%{fill:var(--c1)}13.61%,100%{fill:var(--ce)}}.c.cb{fill:var(--c1);animation-name:cb}@keyframes cc{14.15%{fill:var(--c1)}14.17%,100%{fill:var(--ce)}}.c.cc{fill:var(--c1);animation-name:cc}@keyframes cd{14.44%{fill:var(--c1)}14.46%,100%{fill:var(--ce)}}.c.cd{fill:var(--c1);animation-name:cd}@keyframes ce{21.8%{fill:var(--c1)}21.82%,100%{fill:var(--ce)}}.c.ce{fill:var(--c1);animation-name:ce}@keyframes cf{19.82%{fill:var(--c1)}19.84%,100%{fill:var(--ce)}}.c.cf{fill:var(--c1);animation-name:cf}@keyframes cg{20.67%{fill:var(--c1)}20.69%,100%{fill:var(--ce)}}.c.cg{fill:var(--c1);animation-name:cg}@keyframes ch{14.72%{fill:var(--c1)}14.74%,100%{fill:var(--ce)}}.c.ch{fill:var(--c1);animation-name:ch}@keyframes ci{21.52%{fill:var(--c1)}21.54%,100%{fill:var(--ce)}}.c.ci{fill:var(--c1);animation-name:ci}@keyframes cj{19.25%{fill:var(--c1)}19.27%,100%{fill:var(--ce)}}.c.cj{fill:var(--c1);animation-name:cj}@keyframes ck{15%{fill:var(--c1)}15.02%,100%{fill:var(--ce)}}.c.ck{fill:var(--c1);animation-name:ck}@keyframes cl{15.29%{fill:var(--c1)}15.31%,100%{fill:var(--ce)}}.c.cl{fill:var(--c1);animation-name:cl}@keyframes cm{44.18%{fill:var(--c2)}44.2%,100%{fill:var(--ce)}}.c.cm{fill:var(--c2);animation-name:cm}@keyframes cn{18.4%{fill:var(--c1)}18.42%,100%{fill:var(--ce)}}.c.cn{fill:var(--c1);animation-name:cn}@keyframes co{18.69%{fill:var(--c1)}18.71%,100%{fill:var(--ce)}}.c.co{fill:var(--c1);animation-name:co}@keyframes cp{16.14%{fill:var(--c1)}16.16%,100%{fill:var(--ce)}}.c.cp{fill:var(--c1);animation-name:cp}@keyframes cq{15.85%{fill:var(--c1)}15.87%,100%{fill:var(--ce)}}.c.cq{fill:var(--c1);animation-name:cq}@keyframes cr{23.5%{fill:var(--c1)}23.52%,100%{fill:var(--ce)}}.c.cr{fill:var(--c1);animation-name:cr}@keyframes cs{18.12%{fill:var(--c1)}18.14%,100%{fill:var(--ce)}}.c.cs{fill:var(--c1);animation-name:cs}@keyframes ct{89.79%{fill:var(--c4)}89.81%,100%{fill:var(--ce)}}.c.ct{fill:var(--c4);animation-name:ct}@keyframes cu{16.99%{fill:var(--c1)}17.01%,100%{fill:var(--ce)}}.c.cu{fill:var(--c1);animation-name:cu}@keyframes cv{76.19%{fill:var(--c4)}76.21%,100%{fill:var(--ce)}}.c.cv{fill:var(--c4);animation-name:cv}@keyframes cw{47.02%{fill:var(--c2)}47.04%,100%{fill:var(--ce)}}.c.cw{fill:var(--c2);animation-name:cw}@keyframes cx{35.4%{fill:var(--c1)}35.42%,100%{fill:var(--ce)}}.c.cx{fill:var(--c1);animation-name:cx}@keyframes cy{35.12%{fill:var(--c1)}35.14%,100%{fill:var(--ce)}}.c.cy{fill:var(--c1);animation-name:cy}@keyframes cz{26.34%{fill:var(--c1)}26.36%,100%{fill:var(--ce)}}.c.cz{fill:var(--c1);animation-name:cz}@keyframes c10{33.7%{fill:var(--c1)}33.72%,100%{fill:var(--ce)}}.c.c10{fill:var(--c1);animation-name:c10}@keyframes c11{33.98%{fill:var(--c1)}34%,100%{fill:var(--ce)}}.c.c11{fill:var(--c1);animation-name:c11}@keyframes c12{50.41%{fill:var(--c2)}50.43%,100%{fill:var(--ce)}}.c.c12{fill:var(--c2);animation-name:c12}@keyframes c13{78.46%{fill:var(--c4)}78.48%,100%{fill:var(--ce)}}.c.c13{fill:var(--c4);animation-name:c13}@keyframes c14{49.28%{fill:var(--c2)}49.3%,100%{fill:var(--ce)}}.c.c14{fill:var(--c2);animation-name:c14}@keyframes c15{27.47%{fill:var(--c1)}27.49%,100%{fill:var(--ce)}}.c.c15{fill:var(--c1);animation-name:c15}@keyframes c16{80.44%{fill:var(--c4)}80.46%,100%{fill:var(--ce)}}.c.c16{fill:var(--c4);animation-name:c16}@keyframes c17{27.75%{fill:var(--c1)}27.77%,100%{fill:var(--ce)}}.c.c17{fill:var(--c1);animation-name:c17}@keyframes c18{32.28%{fill:var(--c1)}32.3%,100%{fill:vLine truncated
<svg viewBox="-16 -32 880 192" width="880" height="192" xmlns="http://www.w3.org/2000/svg"><desc>Generated with https://github.com/Platane/snk</desc><style>:root{--cb:#1b1f230a;--cs:purple;--ce:#ebedf0;--c0:#ebedf0;--c1:#9be9a8;--c2:#40c463;--c3:#30a14e;--c4:#216e39}.c{shape-rendering:geometricPrecision;fill:var(--ce);stroke-width:1px;stroke:var(--cb);width:12px;height:12px}.c.c0{fill:var(--c1);animation-name:c0}.c.c1{fill:var(--c2);animation-name:c1}.c.c2{fill:var(--c1);animation-name:c2}.c.c3{fill:var(--c1);animation-name:c3}.c.c4{fill:var(--c1);animation-name:c4}.c.c5{fill:var(--c1);animation-name:c5}.c.c6{fill:var(--c1);animation-name:c6}.c.c7{fill:var(--c1);animation-name:c7}.c.c8{fill:var(--c1);animation-name:c8}.c.c9{fill:var(--c1);animation-name:c9}.c.ca{fill:var(--c1);animation-name:ca}.c.cb{fill:var(--c1);animation-name:cb}.c.cc{fill:var(--c1);animation-name:cc}.c.cd{fill:var(--c1);animation-name:cd}.c.ce{fill:var(--c1);animation-name:ce}.c.cf{fill:var(--c1);animation-name:cf}.c.cg{fill:var(--c1);animation-name:cg}.c.ch{fill:var(--c1);animation-name:ch}.c.ci{fill:var(--c1);animation-name:ci}.c.cj{fill:var(--c1);animation-name:cj}.c.ck{fill:var(--c1);animation-name:ck}.c.cl{fill:var(--c1);animation-name:cl}.c.cm{fill:var(--c2);animation-name:cm}.c.cn{fill:var(--c1);animation-name:cn}.c.co{fill:var(--c1);animation-name:co}.c.cp{fill:var(--c1);animation-name:cp}.c.cq{fill:var(--c1);animation-name:cq}.c.cr{fill:var(--c1);animation-name:cr}.c.cs{fill:var(--c1);animation-name:cs}.c.ct{fill:var(--c4);animation-name:ct}.c.cu{fill:var(--c1);animation-name:cu}.c.cv{fill:var(--c4);animation-name:cv}.c.cw{fill:var(--c2);animation-name:cw}.c.cx{fill:var(--c1);animation-name:cx}.c.cy{fill:var(--c1);animation-name:cy}.c.cz{fill:var(--c1);animation-name:cz}.c.c10{fill:var(--c1);animation-name:c10}.c.c11{fill:var(--c1);animation-name:c11}.c.c12{fill:var(--c2);animation-name:c12}.c.c13{fill:var(--c4);animation-name:c13}.c.c14{fill:var(--c2);animation-name:c14}.c.c15{fill:var(--c1);animation-name:c15}.c.c16{fill:var(--c4);animation-name:c16}.c.c17{fill:var(--c1);animation-name:c17}.c.c18{fill:var(--c1);animation-name:c18}.c.c19{fill:var(--c1);animation-name:c19}.c.c1a{fill:var(--c2);animation-name:c1a}.c.c1b{fill:var(--c1);animation-name:c1b}.c.c1c{fill:var(--c1);animation-name:c1c}.c.c1d{fill:var(--c4);animation-name:c1d}.c.c1e{fill:var(--c4);animation-name:c1e}.u{transform-origin:0 0;transform:scale(0,1);animation-name:u0;transform-origin:0.0px 0}.u.u1{fill:var(--c2);animation-name:u1;transform-origin:648.5px 0}.u.u2{fill:var(--c4);animation-name:u2;transform-origin:748.2px 0}.s{shape-rendering:geometricPrecision;fill:var(--cs);animation-name:s0}.s.s1{transform:translate(16px,-16px);animation-name:s1}.s.s2{transform:translate(32px,-16px);animation-name:s2}.s.s3{transform:translate(48px,-16px);animation-name:s3}</style><rect class="c" x="2" y="2" rx="2" ry="2"/><rect class="c" x="2" y="18" rx="2" ry="2"/><rect class="c" x="2" y="34" rx="2" ry="2"/><rect class="c" x="2" y="50" rx="2" ry="2"/><rect class="c" x="2" y="66" rx="2" ry="2"/><rect class="c" x="2" y="82" rx="2" ry="2"/><rect class="c" x="2" y="98" rx="2" ry="2"/><rect class="c" x="18" y="2" rx="2" ry="2"/><rect class="c" x="18" y="18" rx="2" ry="2"/><rect class="c" x="18" y="34" rx="2" ry="2"/><rect class="c" x="18" y="50" rx="2" ry="2"/><rect class="c" x="18" y="66" rx="2" ry="2"/><rect class="c" x="18" y="82" rx="2" ry="2"/><rect class="c c0" x="18" y="98" rx="2" ry="2"/><rect class="c" x="34" y="2" rx="2" ry="2"/><rect class="c" x="34" y="18" rx="2" ry="2"/><rect class="c" x="34" y="34" rx="2" ry="2"/><rect class="c" x="34" y="50" rx="2" ry="2"/><rect class="c" x="34" y="66" rx="2" ry="2"/><rect class="c" x="34" y="82" rx="2" ry="2"/><rect class="c" x="34" y="98" rx="2" ry="2"/><rect class="c" x="50" y="2" rx="2" ry="2"/><rect class="c" x="50" y="18" rx="2" ry="2"/><rect class="c" x="50" y="34" rx="2" ry="2"/><rect class="c" x="50" y="50" rx="2" ry="2"/><rect class="c c1" x="50" y="66" rx="2" ry="2"/><rect class="c c2" x="50" y="82" rx="2" ry="2"/><rect class="c" x="50" y="98" rx="2" ry="2"/><rect class="c" x="66" y="2" rx="2" ry="2"/><rect class="c" x="66" y="18" rx="2" ry="2"/><rect class="c c3" x="66" y="34" rx="2" ry="2"/><rect class="c c4" x="66" y="50" rx="2" ry="2"/><rect class="c" x="66" y="66" rx="2" ry="2"/><rect class="c c5" x="66" y="82" rx="2" ry="2"/><rect class="c" x="66" y="98" rx="2" ry="2"/><rect class="c" x="82" y="2" rx="2" ry="2"/><rect class="c" x="82" y="18" rx="2" ry="2"/><rect class="c c6" x="82" y="34" rx="2" ry="2"/><rect class="c" x="82" y="50" rx="2" ry="2"/><rect class="c" x="82" y="66" rx="2" ry="2"/><rect class="c" x="82" y="82" rx="2" ry="2"/><rect class="c" x="82" y="98" rx="2" ry="2"/><rect class="c" x="98" y="2" rx="2" ry="2"/><rect class="c" x="98" y="18" rx="2" ry="2"/><rect class="c" x="98" y="34" rx="2" ry="2"/><rect class="c" x="98" y="50" rx="2" ry="2"/><rect class="c" x="98" y="66" rx="2" ry="2"/><rect class="cLine truncated

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 20 KiB