- 远程仓库对单次推送体积有限制,6.7 MB 字体无法一次推送,先从版本库移除 - 新增 tools/build-fonts.py:下载官方分包、合并并子集化,一条命令重建 - @font-face 保留,字体缺失时回退系统字体;离线用例改为按可用性断言
3.1 KiB
3.1 KiB
ADR-0006:视觉风格对齐主题并自托管字体
- 状态:已接受
- 日期:2026-10-25
背景
产品要求前端视觉与参考站点(Alright / nicetheme)一致,包括字体、配色和交互,但不改变既有布局。参考站点使用 Bootstrap 5 + 自定义变量,正文依赖 CDN 的 lxgw-wenkai-webfont,标题使用自托管的 Outfit-Medium。
本项目的目标是"本机、离线可复现":依赖 CDN 会在断网、内网或 CDN 故障时导致字体回退,从而破坏视觉一致性。
决策
- 从参考站点抓取其 CSS 的变量定义,把真实色值映射到本项目既有语义变量(
--primary、--text-main、--border、--success等),布局相关声明一律不改。 - 交互细节对齐主题:
0.3s ease-in-out过渡、主/危险按钮 hover 使用opacity: .85、输入框聚焦使用主色半透明光环、选中项使用主色浅染。 - 字重遵循主题的
--font-weight-bold: 500;标题与指标数字使用Outfit-Medium,正文使用LXGW WenKai,等宽使用主题的SFMono-Regular…Consolas栈。 - 字体全部自托管:
Outfit-Medium.ttf直接取自主题;LXGW WenKai由官方 webfont 的 97 个 woff2 子集合并后,再裁剪到 GB2312 + 常用符号子集,输出简体中文 Regular 与 Bold 两个文件。 - 移除所有 Google Fonts / CDN 字体链接,
index.html只 preload 本地字体文件。 - 新增端到端用例"renders fully offline":拦截并拒绝一切非
127.0.0.1请求,断言页面正常渲染、document.fonts.check命中两种字体且没有任何外部请求。
原因
- 直接用主题的变量值,颜色不会"看起来像"而是确实一致。
- 字体子集化把 8.8 MB 的 194 个子集压到 6.7 MB 的两个文件,仓库与安装包体积可控,浏览器只需一次请求。
- 离线断言把"可复现"变成可回归的测试,而不是口头承诺。
边界
- 字体子集覆盖 GB2312(6763 字)+ Latin + CJK 标点 + 全角符号;更生僻的汉字(GB18030 扩展区)会按浏览器逐字回退到系统字体,显示正常但字形风格不一致。
- 只包含 400 / 700 两个字重,500 / 600 由 CSS 字重匹配落到 400 / 700;主题的 Light(300)未包含。
- 未实现参考站点的暗色模式(
data-scheme="dark")。 - 字体文件随
frontend/public/fonts一起进入安装包,体积增加约 6.7 MB。
后续调整(2026-10-26)
仓库托管的远程仓库对单次推送体积有上限,6.7 MB 的字体二进制无法一次推上去。因此:
- 中文字体二进制 不再纳入版本库(
/frontend/public/fonts/LXGWWenKai-*.woff2已加入.gitignore); - 新增
tools/build-fonts.py,一条命令即可从官方 CDN 重新下载、合并并子集化生成这两个文件; @font-face仍然保留,字体缺失时浏览器回退到系统字体,功能不受影响;- 对应的端到端用例改为「无外部网络渲染」:始终断言没有外部请求,只有字体文件存在时才断言字体命中;
Outfit-Medium.ttf(55 KB)体积很小,继续随仓库提供。