解决 Lighthouse 中的 "Ensure text remains visible during webfont load" 问题。

简述 "Ensure text remains visible during webfont load"
网络字体是浏览器默认不可用的字体。这意味着网络字体必须先下载才能使用。在下载网络字体的过程中,网页上的文本会暂时隐藏,直到网络字体加载完成。
因此,页面看起来加载速度会慢很多,因为对访客来说页面还没有"完成"加载。这可能导致 user experience 下降。当你在 Lighthouse 上分析页面时,会出现关于页面加载性能的警告:"Ensure text remains visible during webfont load"。
通过更改 font-display 值或使用字体加载器可以解决此问题。本文将介绍具体方法。

确保加载网络字体时文本保持可见
在网络字体出现之前,网页设计师只能使用少量预装字体。网络字体让你可以在网站上自由使用任何字体。
这听起来很不错,但网络字体也有缺点;它们会以多种方式降低页面加载速度。
网络字体通常是较大的文件,默认不会安装在计算机上。因此,网络字体必须先下载才能使用。在下载网络字体的过程中,网页上的文本会暂时隐藏,直到网络字体完全加载。这会导致糟糕的 user experience;没有人愿意盯着空白屏幕太久。
网络字体加载并渲染完成后,浏览器会将"不可见文本"替换为使用新网络字体的最终文本。这一时刻被称为 Flash of Invisible Text(FOIT)。正是这个 FOIT 导致了 "Ensure text remains visible during webfont load" 错误消息的出现。

如果你在页面上加载网络字体但没有采取任何措施防止 Flash of Invisible Text,在 Lighthouse 上分析 PageSpeed 时,会出现以下消息:"Ensure text remains visible during webfont load"。它会告诉你在网络字体加载之前让文本可见可以节省多少时间。对于单个字体,这很容易就能节省 100 毫秒。
为什么不可见文本对页面速度不利?
不可见文本实际上不会减慢页面的最终测量加载时间。那么为什么 Lighthouse 认为这是一个大问题?
Google 认为网页提供最佳 user experience 非常重要。通过尽快在页面上显示内容,可以改善 user experience。比较下面我们首页的两个胶片视图:
Flash of Invisible Text
使用 display:swap 消除 Flash of Invisible Text
如你所见,两个页面完成加载的时间完全相同。然而,后一个版本的网站对访客来说看起来要好得多。访客可以立即开始阅读。
这就是为什么明智的做法是无论如何都显示文本——不是使用最终字体,而是使用 "fallback" 字体。这样访客会觉得你的页面加载速度确实非常快。
简要回顾:FOIT 和 FOUT
在继续之前,有必要区分以下概念:FOIT 和 FOUT。FOIT 代表 Flash of Invisible Text,当网络字体在加载过程中不可见时会发生。你可以通过添加 fallback 字体来缓解这个问题。当 fallback 字体被网络字体替换时,这被称为 FOUT,即 Flash of Unstyled Text。
使网络字体在加载时可见
有两种方法可以使网络字体在加载时可见:第一种是通过 CSS font-display 值;第二种是通过类使用 fallback 字体。两种方法各有优缺点,下面将详细讨论。
方法一:Font-display:swap
Font-display 是所有现代浏览器都支持的 CSS 描述符。font-display 描述符根据字体是否已下载以及何时下载来决定字体的显示方式。Font-display 用于 @font-face 规则中。
Font-display 有不同的值:block、swap、fallback 和 optional。使用 swap 值可以避免 FOIT,让文本尽快出现在屏幕上。
一旦我们在 @font-face 规则中设置了 font-display: swap 值,在页面加载过程中系统默认字体将被使用,直到网络字体加载完成。这有助于访客立即阅读页面上的文本。
Google fonts
使用 Google fonts 时,你可以通过在样式表或嵌入代码中简单添加 "&display=swap" 来使用 font-display: swap 方法。
<!-- 通过外部样式表 -->
<link href="https://fonts.googleapis.com/css?family=Open+Sans&display=swap" rel="stylesheet"> <!-- 通过 import 方法 -->
<style>
@import url ('https://fonts.googleapis.com/css?family=Open+Sans&display=swap);
</style>
顺便说一下,我们并不推荐 Google fonts。自行托管网络字体几乎总是更快。它让你对字体的"预加载"过程有更多控制。你可以利用已有的 http/2 连接,而且不需要下载额外的样式表。
本地字体
@font-face {
font-family: "Open Sans";
font-weight: 400;
font-style: normal;
src: url("OpenSans400.woff2") format("woff2");
}
方法二:通过类使用字体
使字体在加载时可见的第二种方法是使用类。这些类通常(但并非总是)添加到 <body> 或 <html> 元素上。
这种方法的优点是你对 fallback 字体和 Flash of Unstyled Text 的时机有更多控制。
这种方法的工作原理如下:在样式表中指定页面初始应使用某种字体(fallback 字体)进行渲染。然后通过 JavaScript FontFace API 或预加载来加载网络字体。字体加载完成后,向页面添加一个类。该类确保网络字体被激活。
你可能会问,为什么要这样做?这样做是为了获得对 fallback 字体的更多控制。你可以使用更大的行间距或不同的字号来显示 fallback 字体,使其更好地匹配网络字体。这可以防止布局偏移。
使用多种网络字体时,你可以使用 FontFace API 方法一次切换所有字体。这节省了大量浏览器重绘。就个人而言,我不推荐这种方法;这确保了 FOUT 在最后一个字体加载完成后才发生。所以这总是比必要的时间更晚。
通过 FontFace API 使用带类的字体:
<style>
//fallback 字体,使用 .9rem 字号
html{
font-family: sans-serif;
font-size:.9rem;
}
//网络字体,使用 1rem 字号
html.fl{
font-family: 'webfont';
font-size:1rem;
}
</style>
<script>
var font = new FontFace("webfont", "url(/font.woff2)", {
style: 'normal', unicodeRange: 'U+000-5FF', weight: '400'
});
// 不要等待渲染树,立即发起请求!
font.load().then(function() {
document.fonts.add(font);
document.documentElement.classList.add("fl")
});
</script> 通过预加载链接
第二种方法是通过预加载链接。如下所述预加载字体。完成后,切换 <html> 元素的类。
<link
rel="preload"
href="/webfont.woff2"
as="font"
type="font/woff2" crossorigin
onload="document.documentElement.classList.add('fl')">
<style>
//fallback 字体,使用 .9rem 字号
html{
font-family: sans-serif;
font-size:.9rem;
}
//网络字体,使用 1rem 字号
html.fl{
font-family: 'webfont';
font-size:1rem;
}
//fontface,在 .fl 类添加到 html 标签后才会激活
@font-face{
font-family:'Open Sans';
font-style:normal;
font-weight:400;
font-display:swap;
src: url(/webfont.woff2) format("woff2");
unicode-range:U+000-00FF;
}</style> 额外提示和技巧
- 始终预加载 https://www.corewebvitals.io/nl/pagespeed/ensure-text-remains-visible-during-web font-load? 可见的字体。字体默认不会在使用之前下载。确定需要网络字体吗?那就预加载它,以便更早可用。
- 想要完全避免 FOIT 和 FOUT?使用 font-display: optional 结合预加载。
- 自行托管网络字体总是比通过 Google fonts 或其他外部 CDN 更快。
Performance is a Feature.
Treating speed as an afterthought fails. Build a performance culture with a dedicated 2-sprint optimization overhaul.
- 2-Sprint Overhaul
- Culture Building
- Sustainable Speed

