CSS字体加载策略:`font-display`与FOIT/FOUT对累积布局偏移(CLS)的影响

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: autofont-display: block 在阻塞周期内的典型表现。虽然 block 最终会显示字体,但最初的空白时间会显著影响用户体验。

  • FOUT (Flash of Unstyled Text): 指的是在自定义字体加载完成之前,文本使用备用字体显示的现象。一旦自定义字体加载完成,文本会瞬间切换到该字体。这是 font-display: swapfont-display: fallbackfont-display: optional 的常见结果。 虽然 FOUT 避免了完全空白的文本,但字体切换可能会引起用户的视觉不适,并导致布局偏移。

累积布局偏移 (CLS) 与字体加载

累积布局偏移 (CLS) 是一个重要的网页性能指标,衡量的是页面在加载过程中发生的意外布局变化。高 CLS 值通常意味着糟糕的用户体验,因为用户可能会在点击链接或按钮时,发现它们的位置突然发生变化。

字体加载是导致 CLS 的一个常见原因。当文本从备用字体切换到自定义字体时,文本的尺寸可能会发生变化,从而导致周围的元素发生移动。

font-display 如何影响 CLS

不同的 font-display 值对 CLS 的影响各不相同:

  • font-display: autofont-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:

  1. 预加载关键字体: 使用 <link rel="preload"> 预加载关键字体,可以告诉浏览器尽快下载这些字体,从而减少 FOIT 和 FOUT。

    <link rel="preload" href="my-custom-font.woff2" as="font" type="font/woff2" crossorigin>
  2. 选择合适的备用字体: 选择与自定义字体在尺寸上尽可能接近的备用字体,可以减少字体切换时发生的布局偏移。可以使用 font-size-adjust 属性来进一步调整备用字体的大小。

  3. 使用字体子集化: 字体文件通常包含大量的字符,但我们的网站可能只需要其中的一部分。使用字体子集化工具可以删除不必要的字符,从而减小字体文件的大小,加快下载速度。

  4. 压缩字体文件: 使用 Gzip 或 Brotli 压缩字体文件,可以进一步减小文件的大小,加快下载速度。

  5. 使用 CDN: 将字体文件托管在 CDN 上,可以利用 CDN 的缓存和全球分布优势,加快字体文件的下载速度。

  6. 考虑 font-size-adjust 属性: 此属性可以调整备用字体的大小,使其更接近自定义字体,从而减少布局偏移。例如:

    body {
      font-family: 'MyCustomFont', sans-serif;
      font-size-adjust: 0.8; /* 根据实际情况调整 */
    }

    font-size-adjust 的值是一个比例因子,用于调整备用字体的大小。

  7. 使用 size-adjustascent-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。

  1. 现状: 我们最初没有设置 font-display,导致 FOIT。用户在页面加载期间会看到空白的文本区域,体验很差。

  2. 改进: 我们首先尝试使用 font-display: swap。这避免了 FOIT,但导致了 FOUT。当 "Open Sans" 加载完成后,文本会从备用字体切换到 "Open Sans",导致布局偏移。

  3. 进一步优化: 我们意识到 "Open Sans" 的行高比备用字体略高。为了减少布局偏移,我们使用了 font-size-adjust 属性,并选择了一个行高更接近 "Open Sans" 的备用字体。

  4. 最终方案: 我们最终采用了以下 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精英技术系列讲座,到智猿学院

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注