先说结论:折腾了三天,最后还是用回了系统默认字体栈。
真是浪费时间,但又觉得不亏——这种矛盾的心情大概就是折腾型技术宅的宿命吧。
起因
上周末发完文章之后,随手打开博客看了一眼,突然觉得正文的字体越看越不顺眼。Reimu 主题默认用的是一套日文字体栈,英文和标点看着还行,但中文的显示效果怎么说呢——就是那种说不上丑但总觉得哪里不太对的感觉。可能是我自己看多了,审美疲劳。
于是乎,一个本来只是打算「花十分钟换个字体」的小项目,变成了持续三天的 CSS 调优马拉松。
尝试路线
第一天:Google Fonts + Noto Sans SC
第一反应是上 Google Fonts 找「最好看的中文字体」。选了 Noto Sans SC,毕竟 Google 出品、字重多、有开源许可,理论上是最稳妥的选择。
步骤很简单:在主题的 head.html 里加一行 Google Fonts 的 link,然后在 custom CSS 里覆盖 body 的 font-family。
结果加载完一刷新页面,好家伙,首页白屏了大概一秒多才渲染出来——字体文件的加载阻塞了首屏渲染。虽然我服务器在美西,但 Google Fonts 的 CDN 在国内加载速度很玄学,快的时候还行,慢的时候能卡好几秒。
这不行,博客本来就没什么流量,首屏再慢,仅有的几个访客直接跑了。
于是研究了一下 font-display: swap 和 preconnect。加上之后白屏问题解决了,但出现了 FOUT(Flash of Unstyled Text)——字体加载前先显示 fallback 字体,加载完突然闪一下变成 Noto Sans。虽然只有几十毫秒的闪烁,但我这种强迫症看着贼难受。
第二天:自托管字体
既然 CDN 有问题,那就自己托管。从 Google Fonts 下载了 Noto Sans SC 的几个字重(300、400、700),用 woff2 格式放到 static/fonts/ 目录下。
自托管的好处是加载快、不受外部 CDN 影响。坏处是——中文字体文件太大了。一个 Noto Sans SC Regular 的 woff2 就有 4MB 多,因为汉字太多了,光 CJK 统一表意文字区就好几万个字符。
4MB 的字体文件对于我这个小水管 VPS 来说,等于每个访客要多加载 4MB 的数据。虽然可以设 cache 和 gzip,但第一次访问的体验还是很差。
尝试了 unicode-range 做子集化,把常用汉字(3000 字左右)单独抽出来做 subset。试了一下,文件缩到了大概 800KB,效果还行。但问题是——万一有人写了生僻字,或者评论里出现了不常用的汉字,就会显示 fallback 字体,看起来很奇怪。
纠结了半天,放弃了。
第三天:回到系统字体
第三天我突然想:我折腾这些干啥呢?绝大多数用户根本不会在意你的博客用的什么字体。而且系统默认字体——比如 macOS 的苹方、Windows 的微软雅黑、Linux 的 Noto Sans CJK——都是各自平台精调过的,阅读体验其实很好。
于是我直接把 font-family 改成了最经典的系统字体栈:
| |
没有额外加载、没有 FOUT、没有白屏时间。每个平台都用自己的最佳字体,渲染速度最快,效果也最稳定。
然后我把前两天的改动全都回滚了,删掉了 fonts 目录,移除了自定义 CSS 里关于字体的部分,顺便清理了一波主题里积攒的垃圾样式。
额外收获:CSS 大扫除
虽然字体最终没换,但这三天的折腾有一个意外的收获——我把 custom CSS 从头到尾清理了一遍。
之前改主题的时候是「想到什么加什么」,积了一堆没用的样式。比如某个页面的边距我之前调了好几次,每次调完旧的注释没删,新的又加上去了。CSS 文件里光是注释掉的代码就有三四十行。
这次全清掉了。重构之后 custom CSS 从原来的 200 多行缩减到了 60 行左右,看的舒服多了。而且清理完之后发现之前有些页面布局奇怪的问题,就是因为旧的样式和新的样式冲突了。删掉多余的之后,页面渲染反而正常了。
总结(如果真的要说总结的话)
这次折腾告诉我一个道理:大多数你觉得「有问题」的地方,其实不是真有问题,是你看了太久看腻了。
字体也好、主题也好、博客样式也好,很多时候你觉得不满意,不是因为真的不好看,而是你天天对着它看,产生了审美疲劳。这时候最好的做法不是去改它,而是先放一放,过几天再看,可能就顺眼了。
当然这个道理我下次大概率还会忘,下次还会继续折腾。没办法,手痒。
最后补一句:如果你的博客也在折腾字体,建议直接从系统字体栈开始,别走我这条弯路。真心的。