# 减少跳动：后备字体和尺寸调整

> 适合谁看：用了 `font-display: swap`，但字体换上来时页面「跳一下」，想减少布局偏移（CLS）的开发者。

## 为什么会跳

备用字体和网页字体的字宽、上下留白不同。换字体时，一行能放下的字数变了，行高也可能变了，后面的内容就整体移动。

对中文来说：

- 汉字基本都是等宽的方块，**中文部分的字宽差别不大**；
- 差别主要来自**西文、数字、标点**的宽度，以及**行高**；
- 如果没有写死 `line-height`，浏览器按字体自带的上下高度计算行高（`line-height: normal`），换字体后每行高度都可能变化。

## 第一步：写死行高

给正文写一个明确的行高，行高就不再依赖字体：

```css
body { line-height: 1.75; }
```

这是最简单、效果最明显的一步。排版上的行高建议见[《正文用字：字号、行距和字重》](https://docs.cocobook.com/link/631)。

## 第二步：选接近的备用字体

备用字体和网页字体越接近，跳动越小：

- 黑体类网页字体，备用写系统黑体（苹方、微软雅黑、思源黑体 / Noto Sans CJK）；
- 宋体、楷体、仿宋类，备用写系统同类字体，见[《中文字体栈怎么写》](https://docs.cocobook.com/link/1254)。

## 第三步：用尺寸调整描述符微调

可以为备用字体单独写一条 `@font-face`，用描述符把它「调」得更像网页字体：

```css
@font-face {
  font-family: "My Sans Fallback";
  src: local("PingFang SC Regular"), local("Microsoft YaHei");
  size-adjust: 100%;
  ascent-override: 88%;
  descent-override: 12%;
  line-gap-override: 0%;
}
body { font-family: "My Sans", "My Sans Fallback", sans-serif; }
```

| 描述符 | 调整什么 |
|---|---|
| `size-adjust` | 整体缩放字形 |
| `ascent-override` | 基线以上的高度 |
| `descent-override` | 基线以下的高度 |
| `line-gap-override` | 行间额外空隙 |

上例中的百分比只是示意，要按两款字的实际度量计算。

浏览器支持情况（据 MDN 兼容性数据）：`size-adjust` 在 Chrome 92、Firefox 92、Safari 17 起支持；`ascent-override` 等三项在 Chrome 87、Firefox 89 起支持，Safari 正式版尚未支持。不支持的浏览器会忽略这些描述符，不会出错。

## 怎么量

- Chrome 开发者工具「性能」面板，或 Lighthouse，查看 CLS（累计布局偏移）；
- 对比开启和关闭网页字体时的截图。

<p class="cb-refs-src" style="display:none;"><a href="https://docs.cocobook.com/link/1307#bkmrk-src-w06-cls">参考资料</a><span class="cb-refs-n">4</span><span class="cb-refs-t">@font-face 的 CSS size-adjust</span><span class="cb-refs-t">@font-face 的 size-adjust 描述符</span><span class="cb-refs-t">@font-face 的 ascent-override 描述符</span></p>