用 font-synthesis 补齐缺失的粗体
博客换成悠哉以后,深色正文里的加粗词很容易扫过去。我用字体扩展给 GitHub 也换了悠哉,那里的粗体却很显眼。两边都请求较高的字重,我就用一句话比较这五个加粗的字。
雨停以后,窗边的书页被风轻轻翻过。
浅色和深色都用 16px,每种主题的正文和粗体用同一个颜色。Light 搭配 Medium 或 Regular 时,差别偏轻。用 Regular 合成粗体后,「窗」和「页」的笔画间隙更紧,但这五个字也容易从句子里看出来。正文换成 Regular 后,整句的粗细更接近博客原来的阅读节奏,所以我选了最后一组。可放大查看 Windows Chrome 的 2× 原图。
先匹配字重,再决定是否合成
悠哉 v0.868 提供 Light、Regular、Medium,没有单独的 Bold。我原先把三份文件登记在同一个家族里,并用 @font-face 把 Medium 声明为 500 900。这个声明告诉浏览器,范围内的字重都能用同一份 Medium 提供。于是粗体请求 700 时,浏览器直接画出 Medium 的轮廓。字面文件见 悠哉 v0.868,匹配规则见 CSS Fonts 4。
我在 Windows Chrome 打开 GitHub 的 Markdown 页面,按字体扩展的规则,把本机悠哉放到中文样句的字体列表最前面。页面对强调文字请求 600,样字实际用的是 Yozai-Regular。加上 font-synthesis-weight: none,计算值还是 600,笔画却回到了 Regular 的粗细。再打开合成,浏览器会把这个字面加厚。测试页面是 GitHub Markup 的 README。
font-synthesis-weight 控制浏览器能否合成缺少的粗体,初始值是 auto,也会被后代继承,定义见 CSS Fonts 4 的合成粗体规则。如果页面本来就允许合成,700 仍然会命中声明覆盖该值的 Medium。要从 Regular 合成,给 strong 选一个只登记 Regular 的家族,同时继续请求粗体。
用 Regular 做正文和合成粗体的底稿
下面是博客字重配置的最小写法。站点的常用字子集和完整字体沿用同样的字重声明,按各自的 unicode-range 加载。
@font-face {
font-family: 'Yozai Prose';
src: url('/fonts/yozai-regular.c7e86c37a9c5.woff2') format('woff2');
font-style: normal;
font-weight: 400;
}
.markdown-body {
font-weight: 400;
font-synthesis-weight: auto;
}
.markdown-body strong {
font-family: 'Yozai Prose', sans-serif;
font-weight: 700;
}
Markdown 的 **…** 会生成 <strong>。这段 CSS 让普通字请求 400,强调字请求 700,两者沿用各自所在段落的颜色。可以在 DevTools 选中强调的汉字,先看 Computed 里的 font-weight,再看 Rendered Fonts 的字面名称。在同一个元素上临时切换 auto 和 none,若计算值与字面相同而笔画粗细有变化,就能看出合成在哪一步起作用。
什么时候该保留合成
合成能补出粗体效果,浏览器决定具体怎样加厚。用只登记 400 的悠哉 Regular 在 Chrome 157 实测,请求 100–500 得到相同的 Regular,请求 600–1000 则得到相同的合成粗体。需要的是稍粗一点的 500 时,还得看字体是否提供相应字面。系统字体遇到这种情况的匹配规则见 系统字体的 font-weight 500 兼容性处理。
如果只想调整粗体回退,用 font-synthesis-weight 就够了。简写 font-synthesis 还控制斜体等合成选项,写成 none 会一并关闭。对于正文里的重点,我会默认允许合成粗体,让读者先看出强调。如果项目要求保持特定的笔画和留白,就选一款提供所需粗体的字体并准确声明字重。浏览器匹配到真实粗体时,会直接使用字体提供的字形。