中文字体子集化之后首屏少了 900KB

性能

引入一款想用的中文字体,woff2 文件 10.6MB。首屏字体请求把渲染堵了将近两秒。

中文字库大是因为字符多,常用汉字三千上下,全量收录是两万多。而一个博客实际用到的字符,把历史文章里出现过的全收集起来,也就一千多个。

子集化就是只保留用到的那些:

pyftsubset font.ttf \
  --text-file=used-chars.txt \
  --flavor=woff2 \
  --output-file=font-subset.woff2

10.6MB 变成 380KB。加上 font-display: swap,首屏不再等字体:

@font-face {
  font-family: 'Brand';
  src: url('/fonts/brand-subset.woff2') format('woff2');
  font-display: swap;
}

代价有三个,都得记着。

新字会掉字体。子集里没有的字符(用户昵称里的生僻字、以后写的文章里的新字)会退回默认字体,一句话里混两种字形,很难看。我的处理是保留一份系统字体栈,并且每次发新文章后重新生成一次字符表——这一步必须自动化,手工做一定会忘。

font-display 的三种行为要想清楚。swap 是先用后备字体显示、加载完替换,会有一次跳字;block 是短暂不可见;optional 由浏览器决定,可能整个页面生命周期都不换。我把标题设 optional、正文设 swap,因为标题跳一下影响不大,正文不能空白。

数字和标点也要在子集里。第一版我漏了破折号和书名号,页面上出现方框。

另一处省下来的:图片。首屏那张封面从 480KB 的 jpg 换成 webp 是 60KB,比字体那一千多 KB 更容易做到。优化顺序应该是"体积最大的先动",而我是先啃了字体。

相关阅读