现代Web字体加载策略优化性能

Web字体可以成就或毁掉你网站的性能。糟糕的字体策略会导致文本不可见、布局偏移和用户体验不佳。然而大多数开发者仍然像2015年那样加载字体——传输庞大的文件,忽略现代CSS特性,只是抱着最好的希望。
本文涵盖了你今天就能实施的实用字体加载策略:利用WOFF2压缩、使用font-display
控制渲染、智能字体子集化、使用系统字体栈作为回退、预加载关键字体,以及在合适的场景下采用可变字体。你将学会如何在性能与排版之间取得平衡,同时改善Core Web Vitals指标。
核心要点
- 仅WOFF2格式就能提供30%更好的压缩率和通用浏览器支持
font-display
属性控制字体加载期间的文本可见性- 字体子集化可以为单语言网站减少70%的文件大小
- 系统字体栈提供即时回退并防止布局偏移
- 当你需要多种字重或平滑动画时,可变字体效果最佳
选择WOFF2并淘汰旧格式
停止传输多种字体格式。WOFF2比WOFF提供30%更好的压缩率,并且拥有通用浏览器支持。除非你需要支持IE11,否则WOFF2就是你所需要的一切。
@font-face {
font-family: 'Inter';
src: url('/fonts/inter.woff2') format('woff2');
font-display: swap;
}
在WOFF2之外还提供TTF、OTF或WOFF格式会浪费带宽。每个访问者都要为几乎不存在的浏览器承担性能代价。使用FontSquirrel或CloudConvert转换现有字体。
使用font-display控制渲染
font-display
描述符决定浏览器如何处理字体请求和渲染之间的间隙:
@font-face {
font-family: 'Inter';
src: url('/fonts/inter.woff2') format('woff2');
font-display: swap; /* 立即显示回退字体 */
}
你的选项:
- swap:立即显示回退文本,准备好时切换(防止FOIT)
- fallback:短暂的不可见期(约100ms),然后回退
- optional:仅在立即可用时使用字体
- block:隐藏文本长达3秒(避免使用)
对于正文文本,使用swap
。对于装饰性字体,考虑optional
。这一行代码就能消除文本不可见的问题。
实施智能字体子集化
大多数网站传输的是完整字符集,但它们永远不会使用。一个完整的拉丁扩展字体可能超过100KB,而你的英文网站可能只需要30KB的字形。
使用unicode-range
按脚本分割字体:
/* 拉丁文 */
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153;
}
/* 拉丁扩展 */
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-latin-ext.woff2') format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF;
}
像Glyphhanger这样的工具可以分析你的内容并生成最优子集。对于Google Fonts,google-webfonts-helper提供预子集化的文件。
Discover how at OpenReplay.com.
设计健壮的系统字体栈
系统字体加载即时且提供优秀的回退。精心设计的字体栈确保即使自定义字体失败也能显示可读文本:
body {
font-family: Inter, -apple-system, BlinkMacSystemFont,
'Segoe UI', Roboto, sans-serif;
}
使用CSS描述符匹配自定义字体和回退字体的度量:
@font-face {
font-family: 'Inter';
src: url('/fonts/inter.woff2') format('woff2');
font-display: swap;
size-adjust: 100.5%; /* 匹配回退字体度量 */
ascent-override: 95%;
descent-override: 25%;
}
使用Font Style Matcher计算这些值并最小化布局偏移。
预加载关键字体
预加载告诉浏览器在CSS中发现字体之前立即获取它们:
<link rel="preload" href="/fonts/inter-latin.woff2"
as="font" type="font/woff2" crossorigin>
关键考虑事项:
- 仅预加载首屏字体
- 包含
crossorigin
属性(字体必需) - 匹配
@font-face
声明中的确切URL - 避免预加载每个子集——这会违背子集化的目的
与内联关键CSS结合使用以获得最大效果:
<style>
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-latin.woff2') format('woff2');
font-display: swap;
}
</style>
策略性考虑可变字体
可变字体可以用一个文件替换多个文件,但它们并不总是更小。支持字重100-900的可变字体可能是50KB,而两个静态字重总计30KB。
@font-face {
font-family: 'Inter Variable';
src: url('/fonts/inter-variable.woff2') format('woff2-variations');
font-weight: 100 900;
font-display: swap;
}
/* 使用范围内的任何字重 */
h1 { font-weight: 750; }
p { font-weight: 425; }
可变字体在以下情况下表现出色:
- 需要多种字重或宽度
- 字重之间的平滑动画
- 随视口缩放的响应式排版
对于使用2-3种字重的简单网站,静态字体通常性能更好。
对Core Web Vitals的影响
正确的字体加载直接改善关键指标:
最大内容绘制(LCP):预加载和font-display: swap
确保文本快速渲染,防止LCP测量延迟。
累积布局偏移(CLS):匹配字体度量和使用size-adjust
消除字体加载时令人不适的文本重排。
首次输入延迟(FID):减少字体载荷并避免阻塞渲染的行为保持主线程响应。
结论
现代字体加载不是选择一个完美策略——而是结合适合你特定需求的技术。从WOFF2和font-display: swap
开始。为关键字体添加子集化和预加载。使用系统字体栈作为可靠回退。仅在可变字体提供明显好处时才考虑使用。
最重要的是,测量影响。使用WebPageTest或Lighthouse验证你的字体策略确实改善了实际性能指标。美观的排版不应该以牺牲用户体验为代价。
常见问题
是的,系统字体栈提供出色的性能和原生渲染。现代系统字体如San Francisco和Segoe UI看起来很专业。但是,自定义字体有助于建立品牌标识和跨平台一致性。
使用unicode-range分割来仅加载所需的字符集。实施语言检测以预加载适当的子集。考虑使用Google Fonts API,它会根据文本内容自动提供优化的子集。
自托管让你完全控制缓存并消除第三方请求。CDN提供自动优化和跨站点共享缓存。为了隐私和性能可预测性选择自托管,为了便利和自动更新使用CDN。
每种字重通常增加15-30KB。加载四种字重意味着总计60-120KB。如果你需要超过三种字重,使用可变字体,或者为了最佳性能将自己限制在两种字重,如常规和粗体。
Understand every bug
Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.