在之前的模块中,您学习了如何优化 HTML、CSS、JavaScript 和媒体资源。在本模块中,您将了解一些优化网页字体的方法。
网页字体可能会在加载时间和渲染时间影响网页性能。
大型字体文件可能需要一段时间才能下载完毕,并会对首次
内容绘制 (FCP) 产生负面影响,而错误的 font-display 值 可能会导致
不必要的视觉渲染偏移。
在讨论如何优化网页字体之前,了解浏览器如何发现网页字体会很有帮助,这样您就可以了解 CSS 如何在某些情况下阻止检索不必要的网页字体。
发现
网页的网页字体是在样式表中使用 @font-face 声明定义的:
@font-face {
font-family: "Open Sans";
src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2");
}
上面的代码段定义了一个 font-family 名为 "Open Sans",并
告知浏览器在哪里可以找到相应的网页字体资源。为了节省带宽,浏览器不会下载网页字体,除非确定当前网页的布局需要该字体。
h1 {
font-family: "Open Sans";
}
在上面的 CSS 代码段中,浏览器会在解析网页 HTML 中的 <h1> 元素时下载 "Open Sans" 字体文件
。
preload
如果您的 @font-face 声明是在外部样式表中定义的,则浏览器只有在下载样式表后才能开始下载这些声明。
这使得网页字体成为后期发现的资源,但有一些方法可以帮助浏览器更快地发现网页字体。
您可以使用 preload 指令来提前请求网页字体资源。preload 指令可让浏览器在网页加载期间尽早发现网页字体,并立即开始下载这些字体,而无需等待样式表下载和解析完毕。preload 指令不会等到网页需要字体时才开始下载。
<!-- The `crossorigin` attribute is required for fonts-even
self-hosted ones, as fonts are considered CORS resources. -->
<link rel="preload" as="font" href="/fonts/OpenSans-Regular-webfont.woff2" crossorigin>
内嵌 @font-face 声明
您可以使用 <style> 元素将渲染阻塞 CSS(包括 @font-face 声明)内嵌到您的 HTML 的 <head> 中,以便在网页加载期间更早地发现字体。在这种情况下,浏览器会在网页加载期间更早地发现网页字体,因为它无需等待下载外部样式表。
内嵌 @font-face 声明比使用 preload 提示具有优势,因为浏览器只会下载渲染当前网页所需的字体。这样可以避免下载未使用的字体。
下载
在发现网页字体并确保当前网页的布局需要这些字体后,浏览器可以下载它们。网页字体的数量、编码和文件大小会显著影响浏览器下载和渲染网页字体的速度。
自行托管网页字体
网页字体可以通过第三方服务(例如 Google Fonts)提供,或 可以在您的来源处自行托管。使用第三方服务时,您的网页需要先打开与提供商网域的连接,然后才能开始下载所需的网页字体。这可能会延迟发现和后续下载网页字体。
可以使用 preconnect 资源提示来减少此开销。通过使用 preconnect,您可以告知浏览器比通常情况下更早地打开与跨源的连接:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
上面的 HTML 代码段提示浏览器建立与
fonts.googleapis.com 的连接以及与 fonts.gstatic.com 的 CORS 连接。某些字体提供商(例如 Google Fonts)会从不同的来源提供 CSS 和字体资源。
您可以自行托管网页字体,从而无需建立第三方连接。在大多数情况下,自行托管网页字体比从跨源下载网页字体更快。如果您计划自行托管网页字体,请检查您的网站是否使用内容分发网络 (CDN)、HTTP/2 或 HTTP/3,并为网站所需的网页字体设置正确的缓存标头。
仅使用 WOFF2
WOFF2 享有 广泛的浏览器支持和最佳压缩率,比 WOFF 高出 30% 。文件大小的减小可缩短下载时间。WOFF2 格式通常是实现与现代浏览器完全兼容所需的唯一格式。
对网页字体进行子集化
网页字体通常包含各种不同的字形,这些字形用于表示不同语言中使用的各种字符。如果您的网页仅提供一种语言的内容,或者仅使用一种字母表,则可以通过子集化来减小网页字体的大小。这通常通过指定一个或一系列 Unicode 代码点来完成。
子集是原始网页字体文件中包含的字形的缩减集。例如,您的网页可能不会提供所有字形,而是提供拉丁字符的特定子集。根据所需的子集,移除字形可以显著减小字体文件的大小。
某些网页字体提供商(例如 Google Fonts)通过使用查询字符串参数自动提供子集。例如,
https://fonts.googleapis.com/css?family=Roboto&subset=latin 网址提供了一个
样式表,其中包含仅使用拉丁字母的 Roboto 网页字体。
如果您已决定自行托管网页字体,则下一步是使用 glyphanger 或 subfont 等工具自行生成和 托管这些子集。
但是,如果您没有自行托管网页字体的能力,则可以通过指定额外的 text 查询字符串参数(仅包含网站所需的 Unicode 代码点)来对 Google Fonts 提供的网页字体进行子集化。例如,如果您的网站上有一个显示网页字体,只需要短语“Welcome”所需的一小部分字符,则可以通过以下网址向 Google Fonts 请求该子集:https://fonts.googleapis.com/css?family=Monoton&text=Welcome。如果这种极端的子集化对您的网站有用,则可以显著减少网站上单个字体所需的网页字体数据量。
字体渲染
浏览器发现并下载网页字体后,即可渲染该字体。默认情况下,浏览器会阻止渲染使用网页字体的任何文本,直到下载完毕。您可以使用 font-display CSS 属性调整浏览器的文本渲染
行为,并配置在网页
字体完全加载之前应显示或不显示哪些文本。
block
font-display 的默认值为 block。使用 block 时,浏览器会阻止渲染使用指定网页字体的任何文本。不同浏览器的行为略有不同。Chromium 和 Firefox 会阻止渲染最多 3 秒,然后使用备用字体。Safari 会无限期阻止,直到网页字体加载完毕。
swap
swap 是最常用的 font-display 值。swap 不会阻止渲染,而是先在备用字体中立即显示文本,然后再替换为指定的网页字体。这样,您就可以立即显示内容,而无需等待网页字体下载完毕。
不过,swap 的缺点是,如果备用网页字体和 CSS 中指定的网页字体在行高、字距调整和其他字体指标方面差异很大,则会导致内容出现明显的偏移。
这通常不会导致比 block 更差的 累积布局偏移 (CLS)(因为 block 需要假设备用字体来布局网页,即使文本本身未显示,因此两者都会受到内容偏移的影响),但视觉效果可能会更令人不适。
fallback
font-display 的 fallback 值是 block 和 swap 之间的一种折衷方案。与 swap 不同,浏览器会阻止字体渲染,但仅在很短的时间内替换为备用文本。不过,与 block 不同,阻止时间非常短。
在快速网络上使用 fallback 值效果很好,在这种情况下,如果网页字体下载速度很快,则网页字体会立即在网页的初始渲染中使用。但是,如果网络速度较慢,则在阻止时间过后,首先会看到备用文本,然后在网页字体到达时将其替换掉。
optional
optional 是最严格的 font-display 值,仅当网页字体资源在 100 毫秒内下载完毕时才使用该资源。如果网页字体加载时间超过此时间,则不会在网页上使用该字体,浏览器会在后台下载网页字体并将其放入浏览器缓存中,同时为当前导航使用备用字体。
因此,后续网页导航可以立即使用网页字体,因为它已下载完毕。font-display: optional 避免了 swap 中出现的视觉偏移,但如果网页字体在初始网页导航中到达时间过晚,则某些用户看不到该字体。
字体演示
知识测验
浏览器何时下载网页字体资源(假设未使用
preload 指令提取该资源)?
向所有现代浏览器提供网页字体所需的唯一(也是最有效)格式是什么?
接下来播放:代码拆分 JavaScript
在掌握字体优化知识后,您现在可以进入下一模块,该模块涵盖了一个主题,该主题很有可能提高用户的初始网页加载速度,即通过代码拆分来延迟加载JavaScript。这样做可以使网页启动阶段的带宽和 CPU 争用尽可能低,因为用户很可能会在此期间与网页互动。