CSS 字体加载策略:font-display 与 FOIT/FOUT 对累积布局偏移 (CLS) 的影响
大家好,今天我们要深入探讨 CSS 字体加载策略,特别是 font-display 属性,以及它如何影响 FOIT (Flash of Invisible Text) 和 FOUT (Flash of Unstyled Text),最终影响网站的累积布局偏移 (CLS)。这是一个非常重要的性能优化领域,直接关系到用户体验。
字体加载的默认行为与问题
在没有明确指定字体加载策略的情况下,浏览器会采取默认行为。当浏览器遇到一个使用了自定义字体的文本时,它会先下载字体文件,然后才渲染文本。这意味着在字体文件下载完成之前,文本是不可见的。这就是所谓的 FOIT。
FOIT 带来的问题显而易见:用户在页面加载期间会看到空白的文本区域,这会造成糟糕的用户体验。用户可能会误以为页面加载失败,或者认为某些内容丢失。
font-display 的作用
font-display 属性允许我们控制字体在加载过程中的显示方式,从而避免 FOIT,并尽可能减少 FOUT 和 CLS。它定义了字体下载的不同阶段,以及在这些阶段中浏览器应该如何处理文本的渲染。
font-display 属性有五个可选值:
auto: 默认值,由浏览器自行决定字体加载策略。通常,这会导致 FOIT。block: 浏览器会有一个短的“阻塞”周期。在此期间,如果字体尚未加载,文本将被隐藏。阻塞周期结束后,浏览器会进入一个无限期的“交换”周期。在此期间,如果字体可用,文本将使用该字体显示;否则,将使用备用字体显示。swap: 浏览器会有一个极短的阻塞周期(通常为 100ms 或更短)。在此期间,如果字体尚未加载,文本将被隐藏。阻塞周期结束后,浏览器会立即进入一个无限期的“交换”周期。在此期间,如果字体可用,文本将使用该字体显示;否则,将使用备用字体显示。fallback: 浏览器会有一个短的阻塞周期和一个短的交换周期。如果在交换周期结束时字体尚未加载,浏览器将使用备用字体显示文本。optional: 浏览器可能会或可能不会下载字体,具体取决于用户的网络连接和设备。如果字体下载速度快,浏览器可能会使用它。否则,浏览器将使用备用字体显示文本。
FOIT 和 FOUT 的详细解析
-
FOIT (Flash of Invisible Text): 指的是在自定义字体加载完成之前,文本完全不可见的现象。这是
font-display: auto或font-display: block在阻塞周期内的典型表现。虽然block最终会显示字体,但最初的空白时间会显著影响用户体验。 -
FOUT (Flash of Unstyled Text): 指的是在自定义字体加载完成之前,文本使用备用字体显示的现象。一旦自定义字体加载完成,文本会瞬间切换到该字体。这是
font-display: swap、font-display: fallback和font-display: optional的常见结果。 虽然 FOUT 避免了完全空白的文本,但字体切换可能会引起用户的视觉不适,并导致布局偏移。
累积布局偏移 (CLS) 与字体加载
累积布局偏移 (CLS) 是一个重要的网页性能指标,衡量的是页面在加载过程中发生的意外布局变化。高 CLS 值通常意味着糟糕的用户体验,因为用户可能会在点击链接或按钮时,发现它们的位置突然发生变化。
字体加载是导致 CLS 的一个常见原因。当文本从备用字体切换到自定义字体时,文本的尺寸可能会发生变化,从而导致周围的元素发生移动。
font-display 如何影响 CLS
不同的 font-display 值对 CLS 的影响各不相同:
-
font-display: auto和font-display: block: 由于存在 FOIT,最初文本是不可见的。当字体加载完成后,文本会突然出现,这可能会导致周围的元素发生移动,从而导致 CLS。 -
font-display: swap: 这是最常用的选项,因为它避免了 FOIT。然而,当自定义字体加载完成后,文本会从备用字体切换到自定义字体,这可能会导致布局偏移,从而导致 CLS。 减少这种CLS的方法是仔细选择后备字体,使其在尺寸上与自定义字体尽可能接近。 -
font-display: fallback: 这个选项在swap的基础上增加了一个交换周期。如果在交换周期结束时字体尚未加载,浏览器将使用备用字体显示文本。这意味着如果字体加载速度较慢,用户将不会看到字体切换,从而减少 CLS。 -
font-display: optional: 这个选项最适合在网络连接较慢的情况下使用。如果字体下载速度快,浏览器可能会使用它。否则,浏览器将使用备用字体显示文本。这可以进一步减少 CLS,但可能会牺牲一些视觉效果。
代码示例
以下是一个使用 font-display: swap 的 CSS 规则示例:
@font-face {
font-family: 'MyCustomFont';
src: url('my-custom-font.woff2') format('woff2'),
url('my-custom-font.woff') format('woff');
font-weight: normal;
font-style: normal;
font-display: swap;
}
body {
font-family: 'MyCustomFont', sans-serif;
}
在这个例子中,我们首先使用 @font-face 规则定义了一个自定义字体。然后,我们将 font-display 属性设置为 swap。这意味着浏览器会先使用备用字体 sans-serif 显示文本,然后在自定义字体加载完成后切换到该字体。
优化字体加载以减少 CLS 的策略
除了使用 font-display 之外,还有其他一些策略可以帮助我们优化字体加载,减少 CLS:
-
预加载关键字体: 使用
<link rel="preload">预加载关键字体,可以告诉浏览器尽快下载这些字体,从而减少 FOIT 和 FOUT。<link rel="preload" href="my-custom-font.woff2" as="font" type="font/woff2" crossorigin> -
选择合适的备用字体: 选择与自定义字体在尺寸上尽可能接近的备用字体,可以减少字体切换时发生的布局偏移。可以使用
font-size-adjust属性来进一步调整备用字体的大小。 -
使用字体子集化: 字体文件通常包含大量的字符,但我们的网站可能只需要其中的一部分。使用字体子集化工具可以删除不必要的字符,从而减小字体文件的大小,加快下载速度。
-
压缩字体文件: 使用 Gzip 或 Brotli 压缩字体文件,可以进一步减小文件的大小,加快下载速度。
-
使用 CDN: 将字体文件托管在 CDN 上,可以利用 CDN 的缓存和全球分布优势,加快字体文件的下载速度。
-
考虑
font-size-adjust属性: 此属性可以调整备用字体的大小,使其更接近自定义字体,从而减少布局偏移。例如:body { font-family: 'MyCustomFont', sans-serif; font-size-adjust: 0.8; /* 根据实际情况调整 */ }font-size-adjust的值是一个比例因子,用于调整备用字体的大小。 -
使用
size-adjust和ascent-override等 CSS 属性 (高级): 这些属性提供了更精细的控制,可以用来调整字体的各种度量,从而减少布局偏移。这需要对字体的内部结构有深入的了解。
不同 font-display 值的比较
为了更清楚地了解不同 font-display 值的影响,我们可以使用一个表格来比较它们的优缺点:
font-display 值 |
优点 | 缺点 | 适用场景 |
|---|---|---|---|
auto |
无 | 可能导致 FOIT,导致 CLS | 不建议使用 |
block |
最终会显示自定义字体 | 可能导致 FOIT,导致 CLS | 不建议使用,除非能接受较长的空白时间 |
swap |
避免 FOIT,始终显示文本 | 可能导致 FOUT,导致 CLS | 适用于大多数情况,但需要注意选择合适的备用字体 |
fallback |
避免 FOIT,如果在短时间内无法加载字体,则使用备用字体,减少 CLS | 如果字体加载速度较慢,用户可能永远看不到自定义字体 | 适用于对 CLS 要求较高的场景,或者网络连接不稳定的场景 |
optional |
如果网络连接良好,则使用自定义字体;否则,使用备用字体,最大程度地减少 CLS | 用户可能看不到自定义字体 | 适用于网络连接较差的场景,或者对视觉效果要求不高的场景 |
案例分析
假设我们有一个电商网站,使用了一种名为 "Open Sans" 的自定义字体。我们希望优化字体加载,减少 CLS。
-
现状: 我们最初没有设置
font-display,导致 FOIT。用户在页面加载期间会看到空白的文本区域,体验很差。 -
改进: 我们首先尝试使用
font-display: swap。这避免了 FOIT,但导致了 FOUT。当 "Open Sans" 加载完成后,文本会从备用字体切换到 "Open Sans",导致布局偏移。 -
进一步优化: 我们意识到 "Open Sans" 的行高比备用字体略高。为了减少布局偏移,我们使用了
font-size-adjust属性,并选择了一个行高更接近 "Open Sans" 的备用字体。 -
最终方案: 我们最终采用了以下 CSS 规则:
@font-face { font-family: 'Open Sans'; src: url('open-sans.woff2') format('woff2'), url('open-sans.woff') format('woff'); font-weight: normal; font-style: normal; font-display: swap; } body { font-family: 'Open Sans', Arial, sans-serif; font-size-adjust: 0.9; /* 根据实际情况调整 */ }我们还使用了
<link rel="preload">预加载 "Open Sans" 字体。
通过这些优化,我们显著减少了 CLS,提高了用户体验。
实际应用中的注意事项
- 测试: 在不同的设备和网络环境下测试你的字体加载策略,以确保它能够正常工作。
- 监控: 使用性能监控工具来监控你的 CLS 值,并根据需要进行调整。
- 迭代: 字体加载优化是一个持续的过程。定期检查你的策略,并根据新的技术和最佳实践进行更新。
- 用户体验至上: 始终将用户体验放在首位。在优化字体加载时,要权衡性能和视觉效果,找到最佳的平衡点。
总结一下
font-display 是一个强大的工具,可以帮助我们控制字体在加载过程中的显示方式,从而避免 FOIT 和 FOUT,减少 CLS,提高用户体验。为了获得最佳效果,我们需要仔细选择 font-display 的值,并结合其他优化策略,如预加载字体、选择合适的备用字体和使用字体子集化。记住,字体加载优化是一个持续的过程,需要不断地测试、监控和迭代。
更多IT精英技术系列讲座,到智猿学院