Featured image of post 优化网页字体加载:防止 FOUT 和 FOITFeatured image of post 优化网页字体加载:防止 FOUT 和 FOIT

优化网页字体加载:防止 FOUT 和 FOIT

使用字体显示和预加载策略确保字体渲染稳定性,防止布局变化。

介绍

网络字体增强了设计,但需要付出代价。加载自定义字体时,浏览器必须决定:显示不可见文本(FOIT - 不可见文本的 Flash)或显示后备字体(FOUT - 无样式文本的 Flash)。任一选择都会影响 CLS(累积布局偏移) 和用户体验。本文介绍了可靠加载字体同时最小化布局变化的策略。


字体显示描述符

@font-face 中的 font-display 属性控制加载过程中字体的显示方式:

@font-face {
  font-family: 'MyFont';
  src: url('/fonts/myfont.woff2') format('woff2');
  font-display: swap;
}
价值行为使用案例
占位符_0浏览器默认(通常为 FOIT)默认
占位符_0不可见文本长达约 3 秒,然后交换区块周期短
占位符_0立即后备字体,准备好后交换最大可读性
占位符_0不可见文本 ~100ms,回退 ~3s,然后交换平衡
占位符_0短块,可选下载连接速度慢

swap 是最常见的选择 - 它立即显示后备文本,然后在加载自定义字体时进行交换,完全消除 FOIT。


预加载关键字体

<head> 中使用 <link rel="preload"> 来提前开始字体下载:

<link rel="preload" href="/fonts/myfont.woff2" as="font" type="font/woff2" crossorigin>

对于从不同来源加载的字体,甚至通过 CDN 提供的同源字体,crossorigin 属性是必需的。如果没有它,预载将被忽略。


自托管与 CDN

方法优点缺点
自托管完全控制,无需额外的DNS查找、缓存控制带宽成本
谷歌字体/CDN快速边缘传送,自动子集额外的 DNS + TLS 握手

对于关键字体,自托管通常表现更好,因为它消除了与字体提供商的额外连接。如果必须使用第三方字体服务,请使用 preconnect

<link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>

字体子集化

将每个字形包含在字体文件中会浪费带宽。 子集化删除未使用的字符:

# Using pyftsubset (fonttools)
pyftsubset Roboto-Regular.ttf --unicodes="U+0020-007E,U+00A0-00FF"

大多数 CDN 字体服务会自动执行此操作。对于自托管字体,请为您支持的每种语言生成子集。 glyphhangerfonttools 等工具可以输出小至 10-20 KB 而不是 100+ KB 的文件。


WOFF2:现代标准

WOFF2(Web 开放字体格式 2)提供比 WOFF 更好 30-50% 的压缩:

@font-face {
  font-family: 'MyFont';
  src: url('/fonts/myfont.woff2') format('woff2'),
       url('/fonts/myfont.woff') format('woff'); /* fallback */
}

所有现代浏览器都支持 WOFF2。使用它作为主要格式,并使用 WOFF 作为备用格式。


通过大小调整防止布局移位

@font-face 中的 size-adjust 描述符可让您标准化指标,以便后备字体和自定义字体占据相同的空间:

@font-face {
  font-family: 'Fallback';
  src: local('Arial');
  size-adjust: 95%;
  ascent-override: 85%;
  descent-override: 20%;
}

使用 size-adjust 计算器(Chrome 开发者工具 > 渲染 > 字体大小调整)等工具来查找正确的值。当字体交换时,这会显着降低 CLS。


完整的优化方案

<head>
  <!-- Preconnect to font origin -->
  <link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>
  <link rel="dns-prefetch" href="https://fonts.googleapis.com">

  <!-- Preload the main font -->
  <link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>
</head>
@font-face {
  font-family: 'Main';
  src: url('/fonts/main.woff2') format('woff2');
  font-display: swap;
}

body {
  font-family: 'Main', 'Fallback', sans-serif;
}

结论

优化 Web 字体需要采用多层方法:使用 font-display: swap 来防止 FOIT、预加载关键字体、对文件进行子集化、提供 WOFF2 并应用 size-adjust 来最小化 CLS。这些技术共同确保了快速、稳定和美观的排版。