一种减少字体加载影响的新方法:CSS 字体描述符

已发表: 2022-03-10
快速总结↬ Web 字体通常对 Web 性能很不利,并且没有一种字体加载策略能特别有效地解决这个问题。 即将推出的字体选项可能最终会兑现使后备字体与最终字体更容易对齐的承诺。

字体加载长期以来一直是 Web 性能的问题,这里确实没有好的选择。 如果您想使用网络字体,您的选择基本上是 Flash of Invisible Text (aka FOIT),其中文本在字体下载之前一直隐藏,或 Flash of Unstyled Text (FOUT),您最初使用后备系统字体,然后将其升级到下载时的网络字体。 说实话,这两种选择都没有真正“获胜”,因为两者都不是真正令人满意的。

font-display不应该解决这个问题吗?

@font-facefont-display属性为 Web 开发人员提供了这个选择,而之前浏览器决定这样做(过去 IE 和 Edge 偏爱 FOUT,而其他浏览器偏爱 FOIT)。 然而,除此之外,它并没有真正解决问题。

许多网站在第一次出现时转移到font-display: swap ,Google 字体甚至在 2019 年将其设为默认值。这里的想法是尽可能快地显示文本对性能更好,即使它在后备字体中,然后在最终下载时交换字体。

我当时也支持这一点,但是当网络字体下载和字符由于字体之间的差异而扩展(或收缩)时,我越来越发现自己对“水合效应”感到沮丧。 与大多数出版商一样,Smashing Magazine 使用网络字体,下面的屏幕截图显示了初始渲染(使用后备字体)和最终渲染(使用网络字体)之间的区别:

两张不同字体的 Smashing Magazine 文章截图。文本的大小明显不同,使用网络字体时可以添加一个额外的句子。
带有后备字体和完整网络字体的 Smashing Magazine 文章。 (大预览)

现在,当并排放置时,网络字体要好得多,并且适合 Smashing Magazine 品牌。 但是我们也看到这两种字体的文本布局有很大的不同。 字体的大小非常不同,因此,屏幕内容会发生变化。 在这个 Core Web Vitals 和 Cumulative Layout Shifts 被(非常正确地!)认为对用户有害的时代, font-display: swap是一个糟糕的选择,因此。

我已经恢复到font-display: block在我照顾的网站上,因为我确实发现文本移动非常刺耳和烦人。 虽然block确实不会停止移位(字体仍然呈现在不可见的文本中),但它至少使它们对用户不那么明显。 我还通过预加载我通过自托管子集字体尽可能小的字体来优化字体加载——因此访问者经常会在很短的时间内看到后备字体。 对我来说, swap的“阻塞期”太短了,老实说,我宁愿多等一会儿才能让初始渲染正确。

跳跃后更多! 继续往下看↓

使用font-display: optional可以解决 FOIT 和 FOUT — 有代价

另一种选择是使用font-display: optional 。 这个选项基本上使网络字体成为可选的,或者换句话说,如果在页面需要它的时候字体不存在,那么浏览器永远不会交换它。 有了这个选项,我们基本上只使用已经下载的字体来避免 FOIT 和 FOUT

如果 web 字体不可用,我们会回退到备用字体,但下一页导航(或重新加载此页面)将使用该字体 - 因为它应该已经完成​​下载。 但是,如果 Web 字体对网站来说并不重要,那么完全删除它可能是个好主意——这对 Web 性能甚至更好!

第一印象很重要,并且完全没有网络字体的初始加载似乎有点太多了。 我也认为——顺便说一句,绝对没有证据支持这一点! ——它会给人们一种印象,也许是潜意识的,网站有些“不对劲”,可能会影响人们使用网站的方式。

因此,所有字体选项都有其缺点,包括根本不使用网络字体或使用系统字体的选项(这是有限制的——但可能不像许多人想象的那样有限制!)。

使您的后备字体更接近您的字体

Web 字体加载的圣杯是使后备字体更接近实际的 Web 字体,以尽可能减少明显的偏移,从而减少使用swap的影响。 虽然我们永远无法完全避免这种转变,但我们可以做得比上面的截图更好。 Monica Dinculescu 的 Font Style Matcher 应用程序经常在字体加载文章中被引用,并让我们对这里应该做的事情有了一个奇妙的一瞥。 它有助于您以两种不同的字体覆盖相同的文本以查看它们的不同之处,并调整字体设置以使它们更紧密地对齐:

字体样式匹配器屏幕截图显示了两组文本重叠在一起,顶部有很大差异,底部有非常相似的文本。
字体样式匹配器屏幕截图,两种字体的默认设置相同(顶部)和调整设置以提供更好的匹配(底部)。 (大预览)

不幸的是,字体样式匹配的问题是我们不能让这些 CSS 样式应用于后备字体,所以我们需要使用 JavaScript 和FontFace.load API 来应用(或恢复)这些样式差异字体加载

代码量不是很大,但感觉还是比应该做的要多一些努力。 尽管正如 Zach Leatherman 在 2019 年的精彩演讲中所解释的那样,为此使用 JavaScript API 还有其他优势和可能性——您可以减少回流并处理data-server模式,并且prefers-reduced-motion (但请注意自从那次谈话以来,两人都接触过 CSS)。

处理我们已经拥有的缓存字体也更棘手,更不用说各种备用样式的差异了。 在 Smashing Magazine 上,我们尝试了许多后备方案,以充分利用不同用户和操作系统已安装的系统字体:

 font-family: Mija,-apple-system,Arial,BlinkMacSystemFont,roboto slab,droid serif,segoe ui,Ubuntu,Cantarell,Georgia,serif;

知道使用哪种字体,或者对每种字体进行单独调整并确保正确应用它们很快就会变得非常复杂。

更好的解决方案即将到来

所以,这是对今天情况的简要追赶。 然而,地平线上开始出现一些烟雾。

正如我之前提到的,应用后备样式差异的主要问题是添加,然后删除它们。 如果我们可以告诉浏览器这些差异仅适用于后备字体怎么办?

这正是作为 CSS 字体模块第 5 级的一部分提出的一组新字体描述符所做的。 这些应用于定义单个字体的@font-face声明。

Simon Hearne 写了关于字体描述规范的提议更新,其中包括四个新的描述: ascent-overridedescent-overrideline-gap-overrideadvance-override (自从放弃)。 您可以使用 Simon 创建的 F-mods Playground 来加载您的自定义和备用字体,然后使用覆盖来获得完美匹配。

正如 Simon 所写,这四个描述符的组合允许我们覆盖后备字体的布局以匹配 Web 字体,但它们只真正修改了垂直间距和定位。 所以对于字符和字母间距,我们需要提供额外的 CSS。

但事情似乎又在发生变化。 最近, advance-override被取消,取而代之的是即将推出的size-adjust描述符,它允许我们通过字形的比例因子(百分比)匹配后备字体和主要 Web 字体来减少布局变化。

它是如何工作的? 假设您有以下 CSS:

 @font-face { font-family: 'Lato'; src: url('/static/fonts/Lato.woff2') format('woff2'); font-weight: 400; } h1 { font-family: Lato, Arial, sans-serif; }

然后你要做的是为 Arial 后备字体创建一个@font-face并将调整器描述符应用于它。 然后,您将获得以下 CSS 片段:

 @font-face { font-family: 'Lato'; src: url('/static/fonts/Lato.woff2') format('woff2'); font-weight: 400; } @font-face { font-family: "Lato-fallback"; size-adjust: 97.38%; ascent-override: 99%; src: local("Arial"); } h1 { font-family: Lato, Lato-fallback, sans-serif; }

这意味着当最初使用Lato-fallback时(因为 Arial 是一种local字体,无需任何额外下载即可立即使用),然后size-adjustascent-override设置允许您将其更接近 Lato 字体。 这是一个额外的@font-face声明,但肯定比我们之前必须跳过的那些箍要容易得多!

总体而言,本规范中包含四个主要@font-face描述符size-adjustascent-overridedescent-overrideline-gap-override ,还有一些其他的仍在考虑用于下标、上标和其他用例.

Malte Ubl 创建了一个非常有用的工具,可以在给定两种字体和支持这些新设置的浏览器的情况下自动计算这些设置(稍后会详细介绍!)。 正如 Malte 指出的那样,计算机擅长这类事情! 理想情况下,我们还可以向 Web 开发人员公开这些常用字体的设置,例如,也许在 Google 字体之类的字体集合中提供这些提示? 这肯定有助于提高采用率。

现在不同的操作系统可能会有稍微不同的字体设置,而将这些设置完全正确基本上是一项不可能完成的任务,但这不是目标。 目的是缩小差距,因此使用font-display: swap不再是一种不和谐的体验,但我们不需要走到optional或没有网络字体的极端。

我们什么时候可以开始使用它?

自版本 87 以来,其中三个设置已在 Chrome 中提供,尽管密钥size-adjust描述符尚未在任何稳定的浏览器中可用。 然而,Chrome Canary 和 Firefox 都有它,所以这不是一个抽象的、遥远的概念,而是很快就会落地的东西。

目前,该规范有各种免责声明和警告,表明它还没有为实时做好准备,但它确实感觉它已经到了那里。 与往常一样,我们、设计师和开发人员之间存在平衡,测试并提供反馈,并阻止使用它,因此实施不会因为太多人最终使用早期草案而陷入困境。

Chrome 已经表示他们打算在 7 月 20 日发布的 Chrome 92 中提供size-adjust功能,这大概表明它几乎就在那里。

所以,还没有完全准备好,但看起来它会在不久的将来出现。 同时,试玩一下 Chrome Canary 中的演示,看看它是否可以更接近解决您的字体加载问题以及它们造成的 CLS 影响。