feat(fonts): 新增六款自托管字族(体积闸门内)(5i T9)

用户拍板「字族扩展都补」。六款按三类各两款落地,全部单页增量 ≤150KB:
小薇(文学·宋体气质)、新晰黑(文学·现代黑)、得意黑(标题)、庆科黄油(标题·圆润)、
马善政毛笔与柳建毛草(书法),许可证均 OFL。

关键取舍:@fontsource 官方中文切片粒度太粗(每片约 33 字、单片 40KB+),一句话命中
7 片即 308–442KB/页,四款全部超闸门;即便用 subset-fonts.py 按站内用字重裁仍剩
205–346KB(笔画类字族单片就 50KB)。故改为从 google/fonts 取原始 TTF,按**字频序
细切**(约 19 字/片、单片 2–12KB),每族 99–100 片、族总量 0.5–1.2MB,浏览器只拉
命中的片。四个 @fontsource 依赖随之移除,package.json 净零变更。

实测单页增量(一句话场景):xiaowei 44.9KB / huangyou 27.1KB / mashanzheng 45.7KB /
liujianmaocao 30.0KB / smiley 27.1KB / neoxihei 30.0KB——全部 PASS;
六族同页共 105KB。

接线(一处漏就静默失效,踩过两次):
- rehype-class-whitelist 放行新类(不放行则 span 的 class 被整条剥掉,页面有字没脸)
- site-content 的 ALLOWED_PAGE_FONTS 与后台排版下拉同源补齐(三处下拉 + hint)
- font-needs 扩六个 key,保证「内容用到才加载」的按需契约继续成立
- global.css 六组规则含 .mom-text 作用域(5h 补的瞬间作用域不能漏)
- typography-classes.js(后台可视化面板单一事实源)35→42 项
- subset-fonts.py 新增 --split-ttf / --slices / --order-from(hwmc 的 --css 用法未动)

覆盖边界(已在 docs 与后台 hint 写明):切片只含站内用字(约 1900 字),
新写生僻字会回落系统字族,需按 docs 命令重切。

验证: 构建 50 页 exit 0;content-lint 51 页 0/0/0;config-check 211 字段/66 hint;
      六类逐项 getComputedStyle 首项 = ZCOOL XiaoWei / ZCOOL QingKe HuangYou /
      Ma Shan Zheng / Liu Jian Mao Cao / Smiley Sans / LXGW Neo XiHei(6/6);
      六族全部出现在 document.fonts;首页字体请求数保持 17(零回归)

Spec: 2026-11-02_blog-5i-fonts-polish (T9)

Co-authored-by: GLM-5.3
This commit is contained in:
wait4xandGLM-5.3 committed 2026-11-03 12:35:20 +08:00
1 parent 073e124344
commit 9df86cb05b
611 files changed
+962 -9

No files matched your search

+22
View File
@@ -225,6 +225,28 @@ pre code { background: none; border: none; padding: 0; font-size: inherit; }
.prose-reading .font-fangsong, .prose-tech .font-fangsong, .rich .font-fangsong, .mom-text .font-fangsong, .prose-body .font-fangsong {
font-family: FangSong, STFangsong, "FangSong_GB2312", serif;
}
/* 5i T9 字族扩展六款(均 OFL / 免费商用且允许 web 嵌入):作用域与上文同款五件套,
含 .mom-text(瞬间富文本容器)。字体族名必须与 @font-face 完全一致,
否则就是“class 在、字形不到”的静默失效(T1 修过的那类)。
四款 @fontsource 自带 unicode-range 切片;得意黑/霞鹜新晰黑 走 public/fonts 手工切片。 */
.prose-reading .font-xiaowei, .prose-tech .font-xiaowei, .rich .font-xiaowei, .mom-text .font-xiaowei, .prose-body .font-xiaowei {
font-family: 'ZCOOL XiaoWei', var(--font-serif);
}
.prose-reading .font-huangyou, .prose-tech .font-huangyou, .rich .font-huangyou, .mom-text .font-huangyou, .prose-body .font-huangyou {
font-family: 'ZCOOL QingKe HuangYou', var(--font-sans);
}
.prose-reading .font-mashanzheng, .prose-tech .font-mashanzheng, .rich .font-mashanzheng, .mom-text .font-mashanzheng, .prose-body .font-mashanzheng {
font-family: 'Ma Shan Zheng', var(--font-kai);
}
.prose-reading .font-liujianmaocao, .prose-tech .font-liujianmaocao, .rich .font-liujianmaocao, .mom-text .font-liujianmaocao, .prose-body .font-liujianmaocao {
font-family: 'Liu Jian Mao Cao', var(--font-kai);
}
.prose-reading .font-smiley, .prose-tech .font-smiley, .rich .font-smiley, .mom-text .font-smiley, .prose-body .font-smiley {
font-family: 'Smiley Sans', var(--font-sans);
}
.prose-reading .font-neoxihei, .prose-tech .font-neoxihei, .rich .font-neoxihei, .mom-text .font-neoxihei, .prose-body .font-neoxihei {
font-family: 'LXGW Neo XiHei', var(--font-sans);
}
/* 文学常用:首字下沉(书评开篇)与金句块(引文式的独立强调段) */
.prose-reading p.drop-cap::first-letter, .prose-tech p.drop-cap::first-letter, .rich p.drop-cap::first-letter, .mom-text p.drop-cap::first-letter, .prose-body p.drop-cap::first-letter {
float: left;