最快的谷歌字体

2020-05-29 02:36:32

在很大程度上,现在的网络字体比以往任何时候都要快。随着浏览器供应商更加标准化的FOUT/FOIT行为,到更新的字体显示规范,性能-因此用户-似乎终于被放在了首要位置。

人们普遍认为自托管字体是最快的选择:相同的来源意味着减少网络协商,可预测的URL意味着我们可以预加载,自托管意味着我们可以设置自己的缓存控制指令,完全所有权可以降低将静态资产留在第三方来源的风险。

这就是说,像谷歌字体这样的服务的便利性怎么夸大都不为过,它们能够为特定的用户代理和平台提供尽可能小的字体文件,这是令人惊叹的,而且有如此庞大的、免费可用的库,这些库是由谷歌级别的CDNS…提供的。我当然明白为什么人们会继续求助于它。

在这个性能是游戏唯一名称的网站上,我完全放弃了网页字体,而是选择使用访问者的系统字体。这是快速的,令人难以置信地非常适合所讨论的设备,并且几乎没有工程开销。但是,在哈里,我真的很想把谨慎抛诸脑后。让它见鬼去吧!让我们有一个网络字体!

在原型开发过程中,我求助于Google字体,他们最近通过URL参数(&;display=swap)支持font-display的能力,我知道它会保持相当快的速度。然后我有了一个主意。

提示:如果您要为Google字体使用`font-display`,那么异步加载整个请求链是有意义的。pic.twitter.com/k6obyVZGZP。

-HarryRoberts(@csswizarry)2020年5月11日。

虽然font-display:exchange;是一个巨大的胜利,但仍然有很多东西让我感到不安。我还能做些什么来让Google字体变得更快呢?

我对harry.is和csswizardry.com主页运行了相同的测试套件。我是从harry开始的,因为那是我使用谷歌字体的地方,但我觉得它太简单了,不太现实。因此,我多次克隆CSS Wizarry主页,并在那里实现了各种不同的方法。对于这篇文章的每个部分,我都会列出两个网站的结果。我的变体是:

此外,每个变体都是相加的-它包括前一个变体以及它自己的添加。我没有尝试只是预加载或异步,因为这是没有意义的-我们知道组合会比他们的任何一个都要好。

First Contentful Paint(FCP):我们多久才能真正读到一些东西,不管它是不是网络字体?

视觉上完整(VC):什么时候一切都确定下来了(一个代理,但与Last Web Font相当)?

注:所有测试都是使用私有WebPagetest实例进行的(WebPagetest目前已关闭,因此我无法使用公共实例,这意味着我无法共享任何URL-抱歉)。具体的配置文件是基于3G的SamsungGalaxy S4。

为了使代码片段更易于阅读,我将用$css替换https://fonts.googleapis.com/css2?family=Roboto:ital,wight@0,400;0,700;1,400;1,700的所有实例。

谷歌字体在过去一年左右的时间里发挥了很大的作用。默认情况下,任何新创建的Google字体片段都带有&;display=swap参数,该参数将font-display:swap;注入到所有@font-face at-Rule中。该参数的值可以是SWAP、OPTIONAL、FLABACK或BLOCK中的任何一个。你可以在MDN上阅读更多。

然而,对于我的基线,我打算重新修剪字体显示。这是许多网站可能仍将使用的遗留格式,它使得比较基准更合适。

好的。这是我们的基线。Google字体文件是这两个测试中唯一拥有的渲染块外部资源,我们可以看到它们都有完全相同的第一个画图。在这些实验中,有一件事让我感到高兴,那就是Google字体的一致性。

第一个是没有网页字体加载解决方案的结果(例如font-display);第二个是同步Google字体CSS文件的结果。

在此测试中,我添加了&;display=exchange。实际上,这使得字体文件本身是异步的-浏览器立即显示我们的回退文本,然后在它到达时切换到Web字体。这意味着我们不会让用户看到任何看不见的文本(Foit),这为Botha带来了更快、更愉快的体验。

注:如果你努力定义一个合适的Fallback来在此期间显示,这只会更令人愉快-在选择Open Sans之前,闪烁一页满是Times New Roman的页面可能会是一种更糟糕的体验。谢天谢地,莫妮卡不仅让这一过程变得简单,而且出人意料地有趣。如果没有她的Font StyleMatcher,我不可能做到这一点。

我们没有从关键路径中删除任何渲染块资源,所以我不希望在First Paint中看到任何改进。事实上,虽然harry.is保持不变,但CSS Wizarry慢了200ms。然而,我们确实看到的是,在第一次满意的绘画中有了戏剧性的进步--比第二次哈雷。是!在harry.is基础上改进的第一种网络字体,但不是oncsswizardry.com。视觉上完整的速度慢了200毫秒。

我很高兴地说,对于最重要的指标,我们的速度要快700-1200毫秒。

虽然这确实大大缩短了呈现Web字体所需的时间,但它仍然是在同步CSS文件中定义的--我们只能期望从这一举措中获得如此大的改善。

引用我自己的话:如果您要对GoogleFonts使用font-display,那么异步加载整个请求链是有意义的。正是这个最初的想法导致了我的tweet-如果我有效地使CSS文件的内容异步,那么让CSS文件本身完全同步就有点糟糕了。

使CSS异步是使用Critical CSS所涉及的关键技术之一。虽然有很多方法可以做到这一点,但我敢说最简单、最普遍的方法就是长丝集团的平面媒体排版。

这将隐含地告诉浏览器以非阻塞方式加载CSS文件,仅将样式应用于打印上下文。但是,一旦文件到达,我们就告诉浏览器将其应用于所有上下文,从而设置页面其余部分的样式。

虽然诀窍非常简单-这就是它如此酷的原因-但我一直有保留意见。你看,一个常规的、同步的样式表会阻塞渲染,所以浏览器会给它最高的优先级。打印样式表(或任何与当前上下文不匹配的样式表)被分配到完全相反的优先级:空闲。

这意味着当浏览器开始发出请求时,异步CSS文件的优先级通常会严重偏低(或者更确切地说,它的优先级是正确的,但可能比您预期的要低得多)。以Vitamix为例,这是一个客户端,我为其实现了自己的字体提供程序的异步CSS:

浏览器正在做我们告诉它的事情:用打印样式表的优先级请求这些CSS文件。因此,在3G连接上,下载每个文件需要几秒钟的时间。浏览器将几乎所有其他内容(包括体内资源)放在我们的打印样式表之前。这意味着这个页面直到3G达到了令人眼花缭乱的12.8秒才呈现出它的自定义字体。

值得庆幸的是,在处理Web字体时,这并不是世界末日:

无论如何,它们都应该被认为是一种增强,所以我们需要能够在没有它们的情况下应付;

然而,对于下面的折叠CSS来说,几乎10秒的延迟是不可接受的-几乎百分之百确定用户将在该时间范围内滚动。

我对这些结果真的很满意。第一个油漆在我们的基线上有了惊人的1.6-1.7的改进,在CSS Wizarry的情况下,比之前的变体提高了1.9秒。第一次满意的油漆比我们的基线提高了2.8分,灯塔得分第一次达到了100分。

然而--这是一个很大的问题--由于降低了CSS文件的优先级,我们的第一个Web字体在CSSWizarry的情况下比我们的基线慢了500ms。这就是印刷媒体黑客攻击的危险所在。

异步加载Google字体是个不错的主意,但是降低CSS文件的优先级实际上减慢了自定义字体的呈现速度。

我要说异步CSS总体上是个好主意,但是我需要一些方法来缓解优先级问题。

好的,如果打印CSS的优先级太低,我们需要的是高优先级的异步获取。输入PRELOAD。

注:我们不能进行全预装,因为它没有得到足够广泛的支持。事实上,在写这篇文章的时候,大约20%的这个网站的访问者将无法使用它。将打印样式表视为一种退路。

注意:将来,我们应该可以使用优先级提示来解决此问题。

虽然First Paint要么保持不变,要么变慢,而First Content_Paint要么保持不变,要么变得更快,在CSS Wizarry的情况下,First Web字体比前一次迭代快了惊人的600ms。

在harry.is的情况下,与我们之前的变体相比几乎没有什么变化。视觉上完整的速度要快200ms,但是任何第一个指标都是原封不动的。正是看到这些结果,实际上促使我也对CSSWizarry进行了测试。因为harry.is是一个如此小而简单的页面,所以对打印样式表没有太多的网络争用-改变它的优先级并没有真正帮助它。

在CSS Wizarry的情况下,我们看到First Paint慢了300ms,这是意想不到的,但却是无关的(没有呈现阻塞CSS,所以更改异步CSS文件的优先级在这里没有任何影响--我要在测试中指出一个异常)。令人高兴的是,First Content Paint改进了200ms,First Web字体快了600ms,视觉完整快了700ms。

我想要解决的最后一块拼图是另一个来源,当我们链接到fonts.googleapis.com获取CSS时,字体文件本身托管在fonts.gstatic.com上。在高延迟连接上,这意味着坏消息。

Google字体对我们有好处-它们通过附加到fonts.googleapis.com响应的HTTP头抢先地初始连接fonts.gstatic.com:

但是,此报头的执行受响应的TTFB限制,在高延迟网络上,TTFB可能非常高。Google字体CSS文件在所有测试中的TTFB中值(包括请求队列、DNS、TCP、TLS和服务器时间)为1406ms。相反,CSS文件的下载时间中值仅为9.5ms-到达文件头所需的时间是下载文件本身的148倍。

换句话说:即使谷歌为我们预先连接了fonts.gstatic.com,他们也只是领先了大约10毫秒。换句话说,这个文件是延迟受限的,而不是带宽受限的。

如果我们实施第一方预连接,我们应该会获得一些可观的巨大收益。让我们看看会发生什么。

我们开始吧!首先,(令人满意的)油漆是真实原封不动的。此处的任何更改都与我们在预连接时的预连无关,只会影响关键路径之后的资源。我们的重点是First Web字体和视觉完备性,这两个方面都有很大的改进。第一个网页字体改进了700-1200毫秒,视觉上完整的字体改进了700-900毫秒,与我们的基准相比,分别改进了600-900毫秒和600-800毫秒。灯塔的得分在100分和99分上都很不错。

使用异步CSS和字体显示使我们容易受到FOUT的影响(或者,如果我们正确设计了后备的话,希望是FOFT)。为了尝试缓解这一问题,我决定使用font-display:Optional;运行一个测试。

这一变化告诉浏览器,网页字体被认为是可选的,如果我们在极小的区块周期内无法获得字体文件,那么我们将不提供交换周期。其实际结果是,如果网页字体加载时间过长,页面浏览量根本不会对其进行调整。这有助于防止FUT,这反过来将为您的用户带来更稳定的体验-他们不会在页面视图中途看到文本重新样式-以及更好的累积布局切换分数(Cumulative Layout Shift Score)。

然而,事实证明,在使用异步CSS时,这总是很麻烦。当打印样式表转换为All样式表时,浏览器会更新CSSOM,然后将其应用于DOM。此时,页面被告知需要一些Web字体,极小的块期开始生效,在页面加载生命周期中途显示Foit。更糟糕的是,浏览器将用最初的备用字体替换Foit,因此用户甚至无法获得新字体的好处。它基本上看起来像是一个窃听器。

想象它比解释它容易得多,所以这里有一张幻灯片的截图:

我不推荐将font-Disply:Optional;与异步CSS一起使用;我建议使用异步CSS。因此,我不推荐font-display:可选;。总的来说,拥有带Fout的非阻塞CSS要比拥有不必要的Foit要好。

虽然自托管您的网页字体很可能是性能和可用性问题的最佳解决方案,但我们能够设计一些具有良好弹性的措施来帮助缓解使用GoogleFonts时出现的许多此类问题。

异步加载CSS、异步加载字体文件、选择FOFT、快速获取异步CSS文件和预热外部域的组合使体验比基线快了几秒钟。

如果Google字体不是您唯一的渲染块资源,如果您违反了FAST CSS的任何其他原则(例如,如果您正在@导入您的Google字体CSS文件),那么您的使用里程将会有所不同。这些优化在Google字体将成为您最大的性能瓶颈之一的项目中是最有益的。

这里结合了许多技术,但生成的代码仍然足够精简和可维护,应该不会造成问题。代码段不需要拆分,可以全部保存在文档的<;head>;中。

<;!-1.抢先预热字体来源。--2.发起CSS文件的高优先级异步抓取。适用于大多数现代浏览器。--3.启动低优先级异步抓取,仅在页面到达后才会应用于页面。适用于所有启用JavaScript的浏览器。--4.万一访问者故意关闭-JavaScript,回退到原来的方法。好消息是,尽管这是一个呈现块请求,但它仍然可以利用-preconnect,这使得它比缺省值稍微快一些。-->;<;!--[1]-->;<;链接版本=";预连接";HREF=";https://fonts.gstatic.com";交叉登录/&><;!--[2]--&><;链接版本=";预加载";AS=";样式";HREF=";$css&;显示=交换"。!--[3]-->;<;link rel=";href=";$css&;display=swap";media=";print";onload=";this.media=';all';&34;/>;<;!--[4]-->;<;noscript>;<。DISPLAY=SWAP";/>;<;/noscript>;