得鹿梦鱼 得鹿梦鱼

字体加载

字体通常是加载缓慢的大型文件。有些浏览器会在字体加载之前隐藏文字, 导致不可见文本 FOIT 闪烁

如何避免显示不可见文本

font-display API 用于指明字体在 font-face 样式中使用时的显示方式。如果自定义字体尚未准备就绪,以下 font-display 值会指示浏览器使用系统字体:

  • swap
  • optional
  • fallback
@font-face {  font-family: "Pacifico";  font-style: normal;  font-weight: 400;  src: local"Pacifico Regular", local"Pacifico-Regular",    urlhttps://fonts.gstatic.com/s/pacifico/v12/FwZY7-Qmy14u9lezJ-6H6MmBp0u-.woff2      format"woff2";  font-display: swap;}

如何避免由延迟字体导致的布局偏移

暂时显示系统字体会将 FOIT 替换为闪烁的无样式文本 FOUT。这样可以更快地呈现内容,从而改进 FCP 和 LCP。 但在自定义字体替换临时系统字体时,FOIT 和 FOUT 都会对 CLS 产生相同的影响。

可以通过将预加载与 font-display: optional 结合使用来缓解字体加载对 CLS 的影响。 不过,过度使用预加载可能会对加载指标产生负面影响。我们建议您进行 A/B 测试,以确保预加载字体不会引入任何性能回归问题

字体最佳实践

  • 延迟文本呈现:如果网页字体尚未加载,浏览器通常会延迟文本呈现。在许多情况下,这会延迟首次内容渲染 FCP。在某些情况下,这会延迟 Largest Contentful Paint LCP
  • 字体切换可能会导致布局偏移并影响 Cumulative Layout Shift CLS。当网页字体及其后备字体在页面上占据不同的空间时,就会发生这些布局偏移

字体加载

字体是重要的资源。如果没有这些字体,用户可能无法查看网页内容。因此,字体加载方面的最佳实践通常侧重于确保尽早加载字体。请特别注意从第三方网站加载的字体,因为下载这些字体文件需要单独的连接设置

了解 @font-face

@font-face 声明是使用任何 Web 字体的必要部分。它至少声明了用于引用字体的名称,并指明了相应字体文件的位置

一个常见的误解是,遇到 @font-face 声明时会请求字体。这不正确。@font-face 声明本身不会触发字体下载。只有当页面上使用的样式引用了某个字体时,系统才会下载该字体

@font-face {  font-family: "Open Sans";  src: url"/fonts/OpenSans-Regular-webfont.woff2" format"woff2";}h1 {  font-family: "Open Sans";}

在上述示例中,只有当网页包含

元素时,才会下载 Open Sans。

因此,在考虑字体优化时,请务必对样式表给予与字体文件本身同等的重视。更改样式表的内容或提交方式可能会对字体送达时间产生重大影响。同样,移除未使用的 CSS 和拆分样式表可以减少网页加载的字体数量

将字体声明和其他关键样式内嵌到主要文档的 中,而不是将其包含在外部样式表中,对大多数网站来说非常有益。这样一来,浏览器便能更快地发现字体声明,因为浏览器无需等待外部样式表下载

**注意:**即使只有部分 CSS 被内嵌,浏览器仍必须等待所有 CSS 加载完毕,才能确定是否需要字体。不建议内嵌字体文件本身。内嵌大型资源(例如字体)可能会延迟主文档的提交,进而延迟其他资源的发现

如果您的网站从第三方网站加载字体,我们强烈建议您使用 preconnect 资源提示与第三方来源建立早期连接。资源提示应放置在文档的 中

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

使用 preload

虽然 preload 在网页加载流程的早期高效地使字体可供发现,但代价是会从加载其他资源中抽走浏览器资源。

内嵌字体声明和调整样式表可能是一种更有效的方法。这些调整更接近于解决发现字体较晚的根本原因,而不仅仅是提供权宜解决方法。

此外,在使用 preload 作为字体加载策略时也应谨慎,因为它会绕过浏览器的一些内置内容协商策略。例如,preload 会忽略 unicode-range 声明,如果谨慎使用,则应仅用于加载单个字体格式

字体提交

字体传送速度越快,文本呈现速度就越快。此外,如果提交字体的时间足够早,有助于消除因字体切换而导致的布局偏移

使用自托管字体

从理论上讲,使用自托管字体应该可以提供更好的性能,因为它可以消除第三方连接设置。在实践中,这两种方案之间的性能差异并不那么明显。例如,Web Almanac 发现,使用第三方字体的网站的呈现速度比使用第一方字体的网站更快。

如果您考虑使用自托管字体,请确认您的网站使用了内容传送网络 CDN 和 HTTP/2。如果不使用这些技术,自托管字体很难提供更好的性能

**注意:**如果您不确定使用自托管字体能否提升性能,请尝试从您自己的服务器提供字体文件,并将传输时间(包括连接设置时间)与第三方字体的传输时间进行比较。如果您的服务器速度较慢,请勿使用 CDN 或 HTTP/2,因为这样自托管字体的性能不太可能更高

使用 WOFF2

在现代字体中,WOFF2 是最新的,支持浏览器最多,并且压缩效果最佳。由于使用 Brotli,WOFF2 的压缩率比 WOFF 高 30%,因此下载的数据量更少,性能也更快

事实上,我们认为现在也该宣告:请只使用 WOFF2,忘记所有其他格式

这样可以极大地简化 CSS 和工作流程,还可以防止意外下载重复或错误的字体。现在,所有平台都支持 WOFF2

子集字体

字体文件通常包含大量字形,用于表示它们支持的所有不同字符。不过,您可能不需要页面上的所有字符,可以通过字体子集来缩减字体文件的大小。

@font-face 声明中的 unicode-range 描述符会告知浏览器字体可用于哪些字符

@font-face {  font-family: "Open Sans";  src: url"/fonts/OpenSans-Regular-webfont.woff2" format"woff2";  unicode-range: U+0025-00FF;}

如果网页包含与 Unicode 范围匹配的一个或多个字符,系统会下载字体文件。unicode-range 通常用于根据网页内容使用的语言提供不同的字体文件。

unicode-range 通常与子集技术结合使用。子字体包含原始字体文件中较小一部分的字形

使用更少的 Web 字体

最快的字体是系统一开始未请求的字体。系统字体和可变字体是可能减少您网站上使用的 Web 字体数量的两种方式。

系统字体是用户设备界面使用的默认字体。系统字体通常因操作系统和版本而异。由于字体已安装,因此无需下载字体。系统字体特别适合用于正文

如需在 CSS 中使用系统字体,请将 system-ui 列为 font-family

font-family: system-ui;

可变字体的理念是,单个可变字体可以替代多个字体文件。可变字体的工作原理是定义“默认”字体样式,并提供用于操控字体的“轴”。例如,具有 Weight 轴的可变字体可用于实现以前需要使用单独的字体来实现的字体效果,例如浅色、常规、粗体和特粗体

字体渲染

当遇到尚未加载的 Web 字体时,浏览器会面临一个两难选择:在 Web 字体到达之前,是否应暂缓渲染文本?或者,在 Web 字体到达之前,应使用回退字体渲染文本

不同的浏览器会以不同的方式处理此场景。默认情况下,如果未加载关联的 Web 字体,基于 Chromium 的浏览器和 Firefox 浏览器会阻止文本呈现最多 3 秒钟。Safari 会无限期阻止文本呈现

您可以使用 font-display 属性配置此行为。此选择可能具有重大影响:font-display 可能会影响 LCP、FCP 和布局稳定性

图标字体

适用于传统 Web 字体的 font-display 策略对图标字体来说效果不太理想。图标字体的后备字体通常与图标字体看起来完全不同,其字符可能传达完全不同的含义。因此,图标字体更有可能导致布局发生重大变化。

此外,使用回退字体可能不切实际。请尽可能将图标字体替换为 SVG,这对无障碍功能也有好处。主流图标字体的较新版本通常支持 SVG

如需减少 CLS 影响,您可以使用 size-adjust 属性

使用 font-display 控制字体性能

决定 Web 字体在加载时的行为可能是一项重要的性能调优技术。借助 @font-face 的新 font-display 描述符,开发者可以根据 Web 字体的加载时间来决定其呈现方式(或回退方式)

借助 Web Fonts,开发者可以将丰富的排版样式纳入到其项目中,但代价是,如果用户还没有字体,浏览器就必须花费一些时间下载该字体。由于网络可能会不稳定,因此此下载时间可能会对用户体验产生不利影响。毕竟,如果文字需要花费过长的时间才能显示,没人会在意文字有多漂亮!

为了降低字体下载缓慢带来的一些风险,大多数浏览器都会实现超时功能,超时后会使用后备字体。这是一种非常实用的技术,但遗憾的是,浏览器在实际实现方面存在差异

浏览器超时(毫秒)后备交换
Chrome 35 及更高版本3 秒
Opera3 秒
Firefox3 秒
Internet Explorer0 秒
Safari不会超时不适用不适用
  • Chrome 和 Firefox 的超时时间为 3 秒,超时后,系统会使用后备字体显示文本。如果字体成功下载,最终会发生切换,并使用预期的字体重新渲染文本。
  • Internet Explorer 的超时时间为 0 秒,因此会立即呈现文本。如果请求的字体尚不可用,则系统会使用回退字体,并在请求的字体可用后重新渲染文本。
  • Safari 没有超时行为(至少不会超出基准网络超时)

字体下载时间表

  1. 第一个周期是字体块周期。在此期间,如果未加载字体,则任何尝试使用该字体的元素都必须改用不可见的回退字体进行渲染。如果字体在屏蔽期间成功加载,则系统会正常使用该字体。
  2. 字体切换期会在字体块期之后立即发生。在此期间,如果未加载字体,则任何尝试使用该字体的元素都必须改用回退字体进行渲染。如果字体在换货期内成功加载,系统会正常使用该字体。
  3. 字体故障期会在字体切换期结束后立即发生。如果此时段开始时字体样式尚未加载,则会被标记为加载失败,从而导致正常的字体回退。否则,系统会正常使用该字体

有效值

auto 会使用用户代理使用的任何字体显示策略。大多数浏览器目前采用的默认策略与屏蔽类似
block 会为字体样式分配较短的块时间(在大多数情况下建议为 3 秒)和无限的换货时间。换句话说,如果字体未加载,浏览器会先绘制“不可见”文本,但会在字体加载后立即切换字体
swap 会为字体样式设置零秒的块周期和无限的换页周期。这意味着,如果未加载字体,浏览器会立即使用回退字体绘制文本,但会在字体加载后立即切换字体
fallback 为字体提供一个非常小的阻塞周期和短暂的交换周期
optional 为字体提供一个非常小的阻塞周期,并且没有交换周期

预加载网页字体以提高加载速度

通常,Web 字体会延迟加载,这意味着在下载关键资源(CSS、JS)之前不会加载
为避免 FOUT,您可以立即预加载所需的 Web 字体。在文档开头为此应用添加 Link 元素

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

as="font" type="font/woff2" 属性会告知浏览器将此资源作为字体下载,并有助于确定资源队列的优先级
crossorigin 属性用于指明是否应使用 CORS 请求提取资源,因为该字体可能来自其他网域。如果没有此属性,浏览器会忽略预加载的字体

通过预加载可选字体来防止布局偏移和不可见文本 FOIT 闪烁

通过优化渲染周期,Chrome 83 消除了预加载可选字体时的布局偏移。 将 <link rel="preload">font-display: optional 结合使用是最有效的方法,可确保在渲染自定义字体时不会出现布局卡顿