自定义字体能让站点更有品牌感,但 MiSans、思源黑体这类中文字体完整包往往 4~8 MB。不做优化时,DevTools 里一条 font 请求就能占掉首屏大半时间。下面是一套可落地的优化路径。
1. 优先 woff2
@font-face {
font-family: 'MiSans';
src: url('/static/fonts/MiSans-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
}
- 只提供
woff2,现代浏览器足够 font-display: swap先用系统字体顶一下,避免长时间 invisible text
2. 按字重拆分文件
正文 400、标题 600/700 各一个文件。加粗样式异步加载:
<link rel="stylesheet" href="/static/fonts/fonts.css">
<link rel="stylesheet" href="/static/fonts/fonts-bold.css" media="print" onload="this.media='all'">
首屏只阻塞 Regular,Semibold 稍后补上,用户感知更顺。
3. 子集化:只留用到的字
用 fonttools 或 glyphhanger 按页面字符集裁剪:
pip install fonttools brotli
pyftsubset MiSans-Regular.woff2 \
--text-file=chars.txt \
--output-file=MiSans-Regular.subset.woff2 \
--flavor=woff2
chars.txt 包含:常用汉字 + 站点导航 + 文章高频字。
完整包 4744 KB → 188 KB 这种量级很常见。
注意:博客持续发新文章时,要定期更新字集或保留稍大的常用字表(如 3500 常用字)。
4. preload 关键字体
<link rel="preload" href="/static/fonts/MiSans-Regular.woff2" as="font" type="font/woff2" crossorigin>
只 preload 首屏一定会用到的那一个 woff2,不要 preload 全部字重。
5. 避免 @import 链
/* ❌ 多一层阻塞 */
@import url('fonts.css');
/* ✅ 在 HTML 里直接 link */
@import 会串行解析,延迟字体请求起点。
6. 长缓存
字体文件带 hash 或版本号时,可设长期缓存:
Cache-Control: public, max-age=31536000, immutable
内容变了改文件名,而不是缩短缓存。
7. 测量方式
Chrome DevTools → Network 筛选 Font,看:
- 下载体积(transferred)
- 是否阻塞渲染
swap后是否出现 FOUT(可接受)还是长时间 FOIT(需优化)
Lighthouse 的「Ensure text remains visible during webfont load」与此直接相关。
对照清单
| 手段 | 作用 |
|---|---|
| woff2 | 体积最小 |
| 子集化 | 体积骤降 |
| 按字重拆分 | 减少首屏下载 |
| preload | 提前握手 |
| font-display: swap | 避免空白字 |
| 长缓存 | 回访几乎零成本 |
字体优化是「一次性辛苦、长期受益」的工作。把 Regular 子集做到 200 KB 以内,再配合 preload,大多数博客站点的字体就不再是性能瓶颈了。
评论