# 加载策略：font-display、预连接和预加载

> 适合谁看：已经能用上网页字体，想让首屏更快、闪动更少的前端开发者。

## font-display 怎么选

| 取值 | 等待字体（期间不显示文字） | 换成新字体的时机 | 适合 |
|---|---|---|---|
| `auto` | 由浏览器决定，常见是 `block` | — | 不建议依赖 |
| `block` | 较长，规范建议约 3 秒 | 字体到了就换 | 图标字体等不能用别的字体代替的场合 |
| `swap` | 极短 | 字体到了就换，不限时间 | 中文正文、标题的默认选择 |
| `fallback` | 极短 | 约 3 秒内到了才换，晚了这次就不换 | 正文，希望减少晚到的跳动 |
| `optional` | 极短 | 基本只在字体已缓存时使用 | 字体可有可无、最在意稳定的页面 |

中文字体体积大、首访很难在 100 毫秒内到达，`optional` 的结果常常是首访看不到字体。一般选 `swap`，再用[《减少跳动：后备字体和尺寸调整》](https://docs.cocobook.com/link/1253) 里的方法降低跳动。

## 预连接

字体放在另一个域名时，在 `<head>` 前部加：

```html
<link rel="preconnect" href="https://字体域名" crossorigin>
```

浏览器会提前完成 DNS、TCP、TLS 握手。字体请求是匿名跨域请求，所以要带 `crossorigin`。

## 预加载：只用在确定的那一个文件上

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

- **适合**：用固定文字裁出来的标题字体、整个西文字体文件等，确定首屏一定会用到的文件。
- **不适合**：按 `unicode-range` 分片的中文字体。页面需要哪几片，要等排版时才知道，手动预加载的那一片多半用不上，反而和关键资源抢带宽。
- 预加载的字体请求即使同源也必须带 `crossorigin`，否则会下载两次。

## 用 JavaScript 控制（可选）

字体加载 API 可以检查和等待字体：

```js
// 等页面上所有字体加载完成
await document.fonts.ready;
// 主动加载某个字重
await document.fonts.load('700 1em "My Sans"');
// 检查是否已可用
document.fonts.check('16px "My Sans"');
```

适合「字体到了再执行动画」「截图前确保字体已加载」这类场景。普通页面用 CSS 就够了。

## 缓存

字体文件很少变化，建议给它们设置长期缓存（例如一年），文件内容变了就换文件名。

<p class="cb-refs-src" style="display:none;"><a href="https://docs.cocobook.com/link/1307#bkmrk-src-w05-loading">参考资料</a><span class="cb-refs-n">5</span><span class="cb-refs-t">CSS Fonts Module Level 4</span><span class="cb-refs-t">优化网页字体</span><span class="cb-refs-t">rel=preconnect</span></p>