生产环境中的可变字体:没人告诉你的取舍
可变字体可以简化你的字体栈并提升设计灵活性,但它们并不会自动带来性能收益。
目录
- 可变字体不是神奇的字体压缩
- 显而易见的好处:更少文件,更有表现力的字体
- 第一个隐藏取舍:一个文件可能比你实际需要的文件更大
- 情况 A:使用多种字重的营销网站
- 情况 B:只使用 regular 和 bold 的产品应用
- 第二个取舍:子集化变得更重要,而不是更不重要
- 第三个取舍:CSS 可能变得过于聪明
- 第四个取舍:渲染差异仍然存在
- 第五个取舍:缓存可能双向影响结果
- 第六个取舍:Lighthouse 不会解释完整故事
- 实用的生产检查清单
- 1. 它替换了哪些静态文件?
- 2. 你会暴露哪些轴?
- 3. 你能安全地子集化吗?
- 4. 是否配置了回退指标?
- 5. `font-display` 是否是有意选择?
- 6. 你测试过低端设备吗?
- 7. 是否有回滚计划?
- 什么时候可变字体是好的生产选择
- 生产经验法则
可变字体不是神奇的字体压缩
可变字体常被介绍为 Web 排版的整洁答案:一个文件,多种字重,更少请求,更顺滑的设计系统。这个说法大方向是对的,但并不完整。
在生产环境中,可变字体与其说是用一个文件替换六个文件,不如说是引入了一套新的排版运行时。你获得了对字重、字宽、倾斜、光学尺寸,以及有时自定义轴的表达控制力。你也同时继承了关于文件大小、浏览器渲染、回退行为、设计治理和性能测量的新决策。
结果可能非常好。也可能比它替换掉的静态方案更差。
如果你当前的网站发送同一字体族的五种字重,一个经过良好子集化的可变字体可能会减少请求并简化 CSS。如果你的网站只发送一个 regular 字重和一个 bold 字重,可变字体可能会为了用户永远用不到的灵活性增加字节数。这就是人们常常跳过的生产取舍。
如果你想了解字体加载策略的更广泛基线,我们关于为什么 web fonts 仍然是大多数网站上最容易获得的性能收益 的指南是一个有用的补充。可变字体不会改变基本原则:发送更少字节,减少渲染延迟,并让回退文本可以接受。
显而易见的好处:更少文件,更有表现力的字体
传统的静态字体配置通常是这样的:
- Regular 400
- Italic 400
- Medium 500
- Semibold 600
- Bold 700
- 也许还有一个单独的 display 字体
每个文件都会独立下载、缓存和渲染。如果页面在首屏使用多个字重,请求会很快堆积起来。
可变字体可以把其中几个字重合并到一个文件里。你不再加载 Inter-Regular.woff2、Inter-Medium.woff2 和 Inter-Bold.woff2,而是加载一个可变字体文件,并在连续范围内使用 font-weight: 400 700。
这会带来真实收益:
- 需要管理的字体文件更少
- 字重之间的插值更一致
- 更细粒度的响应式排版
- 更容易构建主题系统
- 更好地对齐 design-token
对于设计系统来说,这种控制力尤其有用。按钮标签可以使用 580,而不是被迫选择 500 或 600。如果字体支持,狭窄卡片标题可以使用略微压缩的字宽轴。展示型标题可以在可用时使用光学尺寸。
但这些控制能力存在,并不意味着你应该把它们全都用上。
第一个隐藏取舍:一个文件可能比你实际需要的文件更大
可变字体包含一个设计空间的插值数据。这个设计空间是有成本的。单个可变字体文件可能比一两个静态字体文件更大。
当它替换许多文件时,这不是问题。当它替换的是一个克制的字体栈时,这就是问题。
考虑两个常见情况:
情况 A:使用多种字重的营销网站
网站在不同页面使用 300、400、500、600、700 以及斜体。一个经过仔细子集化的可变字体很可能有帮助。它能减少请求开销,并简化未来维护。
情况 B:只使用 regular 和 bold 的产品应用
界面使用 400 和 700,并以系统字体作为回退。可变字体可能会增加不必要的字节。在 Figma 里,灵活性很诱人,但在浏览器里并不总是有用。
错误在于把“一个可变字体文件”与“许多理论上的静态文件”比较,而不是与真实页面当前实际使用的文件比较。
测量关键模板上实际加载的字体字节数。然后用相同字符子集和相同 preload 策略测试可变字体版本。不要假设可变字体版本一定胜出。
第二个取舍:子集化变得更重要,而不是更不重要
可变字体让子集化更有价值,因为基础文件可能包含很多内容:字形、语言支持、OpenType 特性、多个轴以及元数据。
大多数生产网站并不需要字体中的每一个字形。如果你只服务英语,可能不需要完整的泛欧洲字符覆盖、西里尔文、希腊文、越南文以及每个符号区块。如果你确实服务多种语言,也可能仍然希望使用按语言划分的子集,而不是一个通用文件。
实际做法通常是:
- 为大多数用户保留一个核心 Latin 子集。
- 只在内容需要时添加扩展子集。
- 使用
unicode-range让浏览器选择正确的文件。 - 如有需要,为少见文字保留静态回退。
这也是可变字体可能变得棘手的地方。有些字体流水线可以轻松子集化静态字体,却会错误处理可变轴、hinting 或元数据。务必验证输出字体在你计划使用的整个轴范围内仍然表现正确。
一个损坏的子集比一个大字体更糟。它会悄无声息地失败:奇怪的渲染、缺失字形、不一致的字重,或者只在特定 locale 中出现的布局变化。
第三个取舍:CSS 可能变得过于聪明
可变字体通过 CSS 暴露轴。字重、字宽等标准轴可以清晰映射到 font-weight 和 font-stretch 这样的属性。自定义轴通常使用 font-variation-settings。
这种能力会诱使团队变得聪明过头:
.card-title {
font-variation-settings: "wght" 623, "wdth" 92;
}
这在技术上可能是有效的,但很少是一个好的设计系统接口。随机轴值散落在 CSS 中,很难审查、很难重构,也很容易被误用。
更推荐使用 design tokens 或命名工具类:
:root {
--font-weight-body: 400;
--font-weight-heading: 680;
--font-width-compact: 94;
}
.card-title {
font-weight: var(--font-weight-heading);
font-stretch: var(--font-width-compact);
}
尽可能使用标准 CSS 属性。只把 font-variation-settings 留给没有更高层属性的轴。
动画也要谨慎。对字重或字宽做动画,在少量使用时可以很有品位,但也可能导致重排、视觉不稳定,以及在低性能设备上产生不必要的工作。排版不应只因为字体允许,就变成一个动效游乐场。
第四个取舍:渲染差异仍然存在
现代浏览器对可变字体的支持已经很强,但渲染并非处处相同。操作系统文本光栅化器、浏览器引擎、抗锯齿和字体 hinting 都会影响结果。
同一字体族中,可变字体的 500 字重可能看起来并不完全像静态 500 文件。在某些字体族中,静态实例经过人工调校,而插值生成的可变实例是通过数学方式生成的。在小字号下,这种差异可能很重要。
这对正文、导航、密集表格和 UI 标签尤其相关。你的界面文本越密集,就越应该测试真实阅读条件,而不只是测试 hero typography。
如果你在迁移到可变字体的同时重新审视字体系统,请从易读性出发,而不是从新奇感出发。我们的 现代 Web 可读字体实用指南 涵盖了那些不耀眼但通常更重要的选择——行长、字号、对比度、间距——它们往往比拥有 1,000 个可用字重更重要。
第五个取舍:缓存可能双向影响结果
单个可变字体文件可以缓存一次,并在多个页面复用。这是好事。
但如果文件很大且阻塞渲染,首次访问就要预先支付完整成本。静态字体有时可以更有选择性地加载:先为正文加载 regular,之后再加载 bold,只在需要的页面加载 display 字体。
没有通用答案。正确配置取决于流量模式:
- 用户每次会话会访问很多页面吗?共享可变字体文件可能值得。
- 用户是否只打开一篇文章然后离开?更小的静态文件可能更好。
- 首页是否只需要一个字重?不要为了未来页面 preload 一个庞大的设计空间。
- 应用是否在登录后使用,且用户经常重复访问?缓存复用会变得更有价值。
Preload 也需要克制。Preload 首屏文本所需的字体,而不是每一种可能的字体。一次 preload 就是一次优先级声明。太多优先级声明会变成噪音。
第六个取舍:Lighthouse 不会解释完整故事
性能工具可以显示未使用的字体字节、阻塞渲染的请求、布局偏移和网络成本。它们无法告诉你视觉灵活性是否值得这些载荷。
可变字体迁移应通过多种信号来判断:
- 首次视图的字体总传输字节数
- 字体请求数量
- 对 Largest Contentful Paint 的影响
- 字体切换导致的 Cumulative Layout Shift
- 重复访问时的缓存行为
- 与已批准设计的视觉匹配度
- 常见字号下的可读性
如果一次字体迁移后报告变红,不要恐慌。问题可能是 preload 顺序、回退指标或子集不匹配,而不一定是可变字体本身。我们关于 如何阅读 Lighthouse 报告而不恐慌 的指南在这里也相关:把实验室分数当作诊断线索,而不是判决。
实用的生产检查清单
在发布可变字体之前,回答这些问题:
1. 它替换了哪些静态文件?
列出生产中实际使用的文件,而不是设计系统理论上支持的内容。包括字重、样式、字符集和页面模板。
2. 你会暴露哪些轴?
大多数团队应该暴露字重,可能再暴露字宽,很少需要更多。若字体对光学尺寸支持良好,光学尺寸可能有用,但要测试。自定义轴应该有明确的产品目的。
3. 你能安全地子集化吗?
子集化后运行视觉回归检查。测试重音字符、标点、货币符号、包含在字体中的图标,以及所有支持的语言。
4. 是否配置了回退指标?
在适当情况下使用 size-adjust、ascent-override、descent-override 和 line-gap-override 等现代 CSS 工具。良好的回退指标可以减少字体加载期间的布局偏移。
5. font-display 是否是有意选择?
font-display: swap 很常见,但并不总是完美。它提升文本可见性,但如果回退指标很差,可能会产生明显切换。对于非关键字体,如果避免扰动比保证品牌字体更重要,optional 可能可行。
6. 你测试过低端设备吗?
在开发者笔记本上感觉良好的字体,可能在低价 Android 硬件上渲染缓慢。至少测试一台低性能设备或一个限速配置。
7. 是否有回滚计划?
字体变更会影响每个页面。保留旧的静态配置足够长的时间,以便在出现渲染、本地化或性能问题时快速回退。
什么时候可变字体是好的生产选择
在以下情况下,通常值得考虑可变字体:
- 你使用同一字体族的三种或更多字重。
- 你维护一个跨多个模板的设计系统。
- 你需要带有字宽或光学尺寸控制的响应式排版。
- 用户通常每次会话浏览多个页面。
- 你可以正确地子集化并测试字体流水线。
在以下情况下,它们吸引力较低:
- 你只需要 regular 和 bold。
- 可变字体文件比当前配置大得多。
- 该字体在文本字号下插值表现较差。
- 你的团队会把任意轴值散落在 CSS 中。
- 你无法测试本地化和回退行为。
冷静的看法是:可变字体是一种能力,而不是默认优化。它们会奖励那些已经认真管理字体的团队。也会惩罚那些把排版当作装饰、把字体加载当作事后补充的团队。
<!-- tool-cta:start -->
💡 试试这个: 在为生产环境对可变字体进行子集化和打包时,Webfont Generator 会生成带有匹配 CSS 的 WOFF2 输出。
<!-- tool-cta:end -->
生产经验法则
当可变字体能降低复杂度或实现明确的设计结果时使用它。不要因为“一个文件”听起来更干净就使用它。
最好的生产实现往往很朴素:一个经过仔细子集化的可变字体,少量经过批准的轴值,合理的回退,克制的 preload,以及真机测试。这不如无限的排版可能性那么令人兴奋。但它更有可能让你的网站变得更好。