本文讨论了字体的性能最佳实践。Web 字体影响性能的方式有多种:

  • 延迟文本渲染:如果 Web 字体尚未加载,浏览器通常会延迟文本渲染。在许多情况下,这会延迟首次内容绘制 (FCP)。在某些情况下,这会延迟Largest Contentful Paint (LCP)
  • 布局转换:字体交换的做法有可能导致布局偏移。当 Web 字体及其后备字体在页面上占用不同数量的空间时,就会发生这些布局变化。

本文分为三个部分:字体加载、字体传输和字体渲染。每个部分都解释了字体生命周期的特定方面是如何工作的,并提供了相应的最佳实践。

字体加载

在深入研究字体加载的最佳实践之前,了解@font-face工作原理以及这如何影响字体加载非常重要。
@font-face要配合字体类型来工作。它声明了引用字体的名称并指示相应字体文件的加载地址。

  1. @font-face {
  2. font-family: "Open Sans";
  3. src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2");
  4. }

一个常见的误解是在@font-face遇到声明时请求字体—这不是对的。就其本身而言,@font-face声明不会触发字体下载。相反,仅当页面上使用的样式引用字体时才会下载字体。例如,像这样:

  1. @font-face {
  2. font-family: "Open Sans";
  3. src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2");
  4. }
  5. h1 {
  6. font-family: "Open Sans"
  7. }

换句话说,在上面的例子中,Open Sans只有当页面包含一个

元素时才会被下载。
因此,在考虑字体优化时,给样式表和字体文件本身一样多的考虑是很重要的。更改样式表的内容或交付会对字体到达的时间产生重大影响。同样,删除未使用的 CSS 和拆分样式表可以减少页面加载的字体数量。

最佳实践

字体通常是重要的资源,因为没有它们,用户可能无法查看页面内容。因此,字体加载的最佳实践通常侧重于确保尽早加载字体。应特别注意从第三方站点加载的字体,因为下载这些字体文件需要单独的连接设置
如果您不确定页面的字体是否被及时请求,请查看Chrome DevTools 中网络面板中的计时选项卡以获取更多信息。
image.png

内联字体声明

大多数站点在中对内联字体进行声明和使用,而不是将它们包含在外部样式表中。这允许浏览器更快地发现字体声明,因为浏览器不需要等待外部样式表下载。
不建议内联字体文件本身。内联字体等大型资源可能会延迟主文档的传输,并随之延迟其他资源的发现.

与第三方站点提前建立连接

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

  1. <head>
  2. <link rel="preconnect" href="https://fonts.com">
  3. </head>

避免使用预加载加载字体

一般来说,preload应该避免使用资源提示加载字体。尽管preload在页面加载过程的早期使字体可被发现非常有效,但这是以从加载其他资源中占用浏览器资源为代价的。
在大多数情况下,内联字体声明和调整样式表是一种更有效的方法。这些调整更接近于解决晚发现字体的根本原因——而不仅仅是提供一种解决方法。
此外,preload作为字体加载策略也应该谨慎使用,因为它绕过了一些浏览器内置的内容协商策略。例如,preload忽略unicode-range声明,如果谨慎使用,应该只用于加载单一字体格式。

字体传输

更快的字体传输让文本更快的渲染。此外,如果字体传输完成得足够早,这可以帮助消除字体交换导致的布局偏移。

最佳实践

使用自己站点的字体

在页面上,使用自有托管字体可以提供更好的性能,因为它不用建立第三方连接。然而,在实践中,这两个选项之间的性能差异并不那么明显:例如, Web Almanac 发现使用第三方字体的网站比使用第一方字体的字体渲染速度更快。
如果您正在考虑使用自托管字体,请确认您的站点使用的是CDNHTTP/2。如果不使用这些技术,自有托管字体可能不会提供更好的性能。更多信息请参阅内容交付网络
如果您使用自托管字体,建议您还应用第三方字体提供商通常自动提供的一些字体文件优化,例如字体子集设置和 WOFF2 压缩。应用这些优化所需的工作量将在某种程度上取决于您的站点支持的语言。请特别注意,为CJK 语言优化字体可能比较麻烦。
Unicode-range and 字体子集: @font-face 通常与unicode-range描述符一起使用。unicode-range通知浏览器字体可用于哪些字符。

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

如果页面包含一个或多个与 unicode 范围匹配的字符,那么就会下载这份字体。unicode-range通常用于根据页面内容使用的语言提供不同的字体文件。
unicode-range常与子集化技术结合使用。子集字体包括原始字体文件中包含的字形(即字符)的较小部分。例如,一个站点可能只需要拉丁字符和西里尔字符生成单独的子集字体这一小部分。每个字体的字形数量变化很大:拉丁字体通常每个字体有 100 到 1000 个字形;CJK字体可能有超过 10,000 个字符。删除未使用的字形可以显着减小字体的文件大小。
生成字体子集的工具包括subfontglyphaner
有关 Google Fonts 如何实现字体子集的信息,请参阅此演示文稿。对于 Google Fonts API 子集,请参阅此repo
WOFF2:在现代字体中,WOFF2是最新的,拥有最广泛的浏览器支持,并提供最好的压缩。由于使用了 Brotli,WOFF2 的压缩率比 WOFF 好 30%。

使用更少的网络字体

交付最快的字体是不用被请求的字体。系统字体和变量字体是两种可以减少您网站上使用的网络字体数量。
系统字体是用户界面中使用的默认字体。系统字体通常因操作系统和版本而异。因为已经安装了字体,所以不需要下载字体。系统字体尤其适用于正文。
要在 CSS 中使用系统字体,范例如下:

  1. font-family: system-ui

可变字体背后的想法是单个可变字体可以用作多个字体文件的替代品。可变字体通过定义“默认”字体样式并提供用于操作字体的“axes”来工作。例如,Weight可以使用带有轴的可变字体来实现以前需要单独的浅色、常规、粗体和超粗体字体的字体。
并非每个人都会从切换到可变字体中受益。可变字体包含多种样式,因此通常比仅包含一种样式的单个非可变字体具有更大的文件大小。使用可变字体将获得最大改进的站点是那些使用(并且需要使用)各种字体样式和粗细的站点。

字体渲染

当面对尚未加载的 Web 字体时,浏览器会面临两难境地:它是否应该在 Web 字体下载完之前推迟渲染文本?或者它应该以备用字体呈现文本,直到网络字体下载完?
不同的浏览器以不同的方式处理这种情况。默认情况下,如果相关的 Web 字体尚未加载,基于 Chromium 的浏览器和 Firefox 浏览器将阻止文本渲染长达 3 秒;Safari 将无限期地阻止文本呈现。
可以使用font-display属性来配置此行为。这种选择可能具有重大意义:font-display有可能影响 LCP、FCP 和布局稳定性。

最佳实践

选择合适的font-display策略

font-display 通知浏览器在关联的 Web 字体尚未加载时应如何进行文本呈现。它是按字体定义的。

  1. @font-face {
  2. font-family: Roboto, Sans-Serif
  3. src: url(/fonts/roboto.woff) format('woff'),
  4. font-display: swap;
  5. }

font-display有五种值

Value Block period Swap period
Auto Varies by browser Varies by browser
Block 3 seconds Infinite
Swap 0ms Infinite
Fallback 100ms 3 seconds
Optional 100ms None
  • Block period: 阻止期从浏览器请求 Web 字体时开始。在阻塞期间,如果网页字体不可用,则该字体以不可见的后备字体呈现,因此用户将看不到文本。如果字体在周期结束时不可用,它将以后备字体呈现。
  • Swap period: 如果网络字体在交换期间可用,它将被“替换”进来。

    建议

    font-display策略反映了关于性能和美学之间权衡的不同观点。对于大多数站点,以下是最适用的两种策略:

  • 如果性能是重中之重:使用font-display: optional. 这是最“高效”的方法:文本渲染延迟不超过 100 毫秒,并且可以保证不会出现与字体交换相关的布局变化。

  • 如果以 Web 字体显示文本是重中之重:使用font-display: swap但确保尽早交付字体,以免导致布局偏移。

还要记住,这两种方法可以结合使用:例如,font-display: swap用于品牌和其他视觉上与众不同的页面元素;font-display: optional用于正文中使用的字体。