网页字体的性能困境

网页字体(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;
}

四、注意事项

  1. FOUT 比 FOIT 更好:用户宁愿先看到系统字体的文字,也不愿看到空白
  2. 限制字重数量:每增加一个字重(bold、semibold 等)都意味额外的下载
  3. 使用 variable fonts:可变字体一个文件包含多个字重,大幅减少请求数
  4. 缓存策略:字体文件应设置长缓存时间(一年以上),因为字体很少更新

五、总结

网页字体优化需要在设计品质和加载性能之间找到平衡点。建议从最基础的措施开始——使用 WOFF2 格式、设置 font-display: swap、预加载关键字体。对于中文等大字符集字体,子集化几乎是必须的优化步骤。通过组合使用这些策略,你可以在不影响品牌视觉效果的前提下,将字体加载对页面性能的影响降到最低。