谢天谢地,如今我们对字体加载有了更多控制。我们不再需要强迫用户等待字体加载完毕才能显示文本,我们可以随着字体加载而进行替换。但这种替换可能会带来视觉上的突兀,出现很多突然的切换和重排。不过我们可以解决这个问题!
在网页上加载自定义字体时,负责任的做法是确保@font-face
声明使用属性font-display
,将其设置为swap
或optional
之类的值。
@font-face {
font-family: 'MyWebFont'; /* Define the custom font name */
src: url('myfont.woff2') format('woff2'); /* Define where the font can be downloaded */
font-display: swap; /* Define how the browser behaves during download */
}
这样设置后,用户加载页面时,不会出现延迟,他们就能看到文本。这对性能来说很棒。但它也存在设计上的权衡,用户会看到 FOUT,即“未定义文本闪烁”。也就是说,他们会看到页面加载时使用了一种字体,然后字体加载完成,页面会将这种字体切换为新的字体,从而造成一些视觉干扰,可能还会出现一些重排。
这个技巧的目的是最大程度地减少这种干扰和重排!
这个技巧来自于Glen Maddern,他在Front End Center上发布了一个关于此技巧的视频,他将 Monica Dinculescu 的字体样式匹配工具与 Bram Stein 的Font Face Observer 库结合使用。
假设您从 Google Fonts 加载字体。这里我将使用Rubik,两种字重。
@import url("https://fonts.googleapis.com/css2?family=Rubik:wght@400;900&display=swap");
在该 URL 的末尾,默认情况下您会看到&display=swap
,这就是它们确保@font-face
声明中包含font-display: swap;
的方式。
在连接速度较慢的情况下,以下是包含文本的简单页面加载方式
看到切换了吗?请记住,从某种意义上说,这是好的,因为至少文本从一开始就是可见的。但这种切换过于强硬,感觉视觉上很突兀。

在页面首次绘制之前。

页面将在自定义字体加载时使用回退字体进行绘制。font-display: swap
有一个“极小的阻塞时间”,因此除非字体在浏览器缓存中,否则您几乎肯定会看到切换发生(FOUT)。

自定义字体加载完成后,页面将重新绘制,导致重排和视觉上的抖动。除非我们解决它!
让我们解决这个问题。
使用字体样式匹配工具,我们可以将两种字体叠加在一起,看看 Rubik 和回退字体之间的差异。

请注意,这里我使用system-ui
作为回退字体。您应该使用经典的“网络安全”字体作为回退字体,例如 Georgia、Times New Roman、Arial、Tahoma、Verdana 等。大多数计算机默认安装了这些字体,因此它们是安全的回退字体。
在我们的案例中,这两种字体的“x 高度”几乎完全相同(注意红色和黑色小写字母的高度)。如果它们不同,我们就需要调整字体大小和行高以匹配。但幸运的是,我们只需要调整一下字间距就能让它们非常接近。
将回退字体调整为使用letter-spacing: 0.55px;
,让它们的大小非常接近!

现在,诀窍是在字体加载之前应用这种样式。因此,让我们将其设置为默认样式,然后使用一个 body 类告诉我们字体已加载,并移除修改。
body {
font-family: "Rubik", system-ui, sans-serif;
letter-spacing: 0.55px;
}
body.font-loaded {
letter-spacing: 0px;
}
但如何获得font-loaded
类呢?Font Face Observer 库使它变得非常容易,并且跨浏览器兼容。使用该库后,只需几行 JavaScript 就可以调整类。
const font = new FontFaceObserver("Rubik", {
weight: 400
});
font.load().then(function() {
document.body.classList.add("font-loaded");
});
现在看看字体加载体验变得多么平滑和不那么突兀了

这是首次绘制和字体加载后的状态叠加在一起。在标题中,您可以看到绿色阴影/字体已加载的标题移动了很多。我们可以解决这个问题。但更重要的是,正文文本并没有出现太多重排。它会导致一些明显的切换,但所有行和位置都保持不变,所以没有人会迷路。
这是一个非常棒的技巧!
以下是这个简短的演示
在测试时,如果您看不到切换发生,请检查您是否已在机器上安装了 Rubik 字体。或者您的网络可能太快了!开发人员工具可以帮助您降低网络连接速度以进行测试。

当您使用多种字体和多种字重的字体时,事情会变得更加复杂。您可以观察每个字体的加载情况,并在它们加载时调整不同的类,调整样式以确保重排尽可能少。