网页字体的性能困境
网页字体(Web Font)是现代网站设计中不可或缺的元素,它能显著提升品牌的视觉识别度和页面的设计质感。然而,字体文件往往是页面中体积较大的资源之一——一个完整的字体族(包含常规、粗体、斜体等多个字重)总大小可能达到 1-2MB,中文字体文件更是动辄 5-10MB。
未优化的字体加载会导致 FOIT(Flash of Invisible Text,文字不可见闪烁)或 FOUT(Flash of Unstyled Text,无样式文字闪烁)现象,严重影响用户体验和 Core Web Vitals 中的 LCP 指标。根据 Google 的研究,字体加载优化可以使 LCP 平均提升 15-20%。本文将详细介绍网页字体的优化加载策略。
一、字体加载的核心概念
1.1 字体显示策略
CSS 提供了 font-display 属性来控制字体加载期间的文字显示行为:
| 属性值 | 行为 | 适用场景 |
|---|---|---|
auto |
浏览器默认策略(通常是 FOIT) | 通用场景 |
block |
短暂阻塞(~3s 不可见,之后降级) | 品牌字体关键使用 |
swap |
立即显示降级字体,加载后替换 | 大多数场景(推荐) |
fallback |
短暂阻塞,若超时则长期使用降级字体 | 平衡美观与性能 |
optional |
极短阻塞,若超时则不再加载 | 追求极致性能 |
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont.woff2') format('woff2');
font-display: swap; /* 推荐大多数场景使用 */
}
1.2 字体格式对比
| 格式 | 压缩率 | 浏览器支持 | 说明 |
|---|---|---|---|
| WOFF2 | 最佳 | 现代浏览器均支持 | 首选格式 |
| WOFF | 好 | 广泛支持 | 兼容旧浏览器 |
| TTF/OTF | 无压缩 | 全支持 | 不推荐用于 Web |
| EOT | 一般 | 仅 IE | 已淘汰 |
二、优化策略
2.1 字体子集化
对于中文字体,子集化是最有效的优化手段。中文字体包通常包含 20000+ 字符,但一个典型网站实际使用的字符不到 2000 个。通过子集化可以移除未使用的字符,将字体文件缩小 90% 以上:
# 使用 glyphhanger 提取页面使用的字符
glyphhanger --whitelist="常用汉字和标点" --subset=*.ttf --format=woff2
2.2 预加载关键字体
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>
2.3 字体加载策略组合
| 方案 | 复杂度 | 性能 | 可维护性 | 适用场景 |
|---|---|---|---|---|
| font-display: swap | 低 | 高 | 高 | 所有项目 |
| 字体子集化 | 中 | 极高 | 中 | 中文/日文等大字符集 |
| 预加载关键字体 | 低 | 高 | 高 | 首屏文字 |
| 内联关键字体 | 高 | 极高 | 低 | 首屏字体极少时 |
| 自托管字体 | 中 | 高 | 中 | 避免第三方依赖 |
2.4 自托管 vs 第三方字体服务
<!-- Google Fonts 加载(不推荐用于性能敏感项目)-->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet">
<!-- 自托管时只需使用 @font-face -->
<style>
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-regular.woff2') format('woff2');
font-display: swap;
unicode-range: U+0000-00FF; /* 限制 Unicode 范围 */
}
</style>
三、代码示例
// 使用 Font Face Observer 检测字体加载完成
import FontFaceObserver from 'fontfaceobserver';
const font = new FontFaceObserver('MyFont');
font.load(null, 3000).then(() => {
document.documentElement.classList.add('fonts-loaded');
}).catch(() => {
document.documentElement.classList.add('fonts-failed');
});
/* 字体加载前使用系统字体 */
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}
/* 字体加载后切换 */
.fonts-loaded body {
font-family: 'MyFont', sans-serif;
}
四、注意事项
- FOUT 比 FOIT 更好:用户宁愿先看到系统字体的文字,也不愿看到空白
- 限制字重数量:每增加一个字重(bold、semibold 等)都意味额外的下载
- 使用 variable fonts:可变字体一个文件包含多个字重,大幅减少请求数
- 缓存策略:字体文件应设置长缓存时间(一年以上),因为字体很少更新
五、总结
网页字体优化需要在设计品质和加载性能之间找到平衡点。建议从最基础的措施开始——使用 WOFF2 格式、设置 font-display: swap、预加载关键字体。对于中文等大字符集字体,子集化几乎是必须的优化步骤。通过组合使用这些策略,你可以在不影响品牌视觉效果的前提下,将字体加载对页面性能的影响降到最低。