嘿!这整篇文章都是关于 2019 年 5 月之前的一段时间,当时 Google Fonts 并没有提供在不自行托管字体的情况下使用 font-display 的方法。
要将 font-display 与 Google Fonts 结合使用,您需要在 URL 中包含一个 URL 参数,例如 &display=swap
,例如 https://fonts.googleapis.com/css?family=Open+Sans&display=swap。如果您现在正在从 Google Fonts 复制代码,那么这是默认设置,因此您会自动获得它,但是如果您有现有的 Google 字体 URL 徘徊,或者您想将其更改为 类似于 optional
的内容,您可能需要添加它。
Zach Leatherman 指出,我们仍然有一些 希望的事情,例如字体的稳定 URL,这样我们就可以在自己的 CSS 中链接字体,从而避免目前所需的双跳。
这是原始文章
font-display
描述符在 @font-face
块中真的很棒。它本身就能为提高网页字体加载的感知性能做出巨大贡献。加载网页字体是一件棘手的事情,拥有像这样工作得这么好的工具对网络来说意义重大。
这件事意义重大,以至于 Google 自家的 Pagespeed Insights / Lighthouse 会因为您没有使用它而惩罚您。具有讽刺意味的是,它们自己的 Google Fonts(毫无疑问是网络上最常用的自定义字体库)并没有提供任何使用 font-display
的方法。
由 Daniel Dudas 在此处总结
Google Developers 建议使用 Lighthouse -> Lighthouse 警告在加载字体时没有使用
font-display
-> 网页使用 Google Fonts 的方式是在 Google Fonts 上建议的 -> Google Fonts 不支持font-display
-> 真是让人头疼。
本质上,我们开发者希望有一种方法可以在 Google 提供的 @font-face
块中获得 font-display
,就像这样
@font-face {
font-family: "Open Sans Regular";
src: url("...");
font-display: swap;
}
或者,某种同样容易且同样有效的替代方案。
查询参数似乎是一种可能性
当您使用 Google 字体时,它们会为您提供一个 URL,该 URL 会生成一个样式表并使字体生效。就像这样
https://fonts.googleapis.com/css?family=Roboto
它们还支持 URL 参数来执行各种操作,例如加粗
https://fonts.googleapis.com/css?family=Open+Sans:400,700
以及子集
http://fonts.googleapis.com/css?family=Creepster&text=TRICKS
https://fonts.googleapis.com/css?family=Open+Sans:400,700&subset=cyrillic
所以,为什么不…
http://fonts.googleapis.com/css?family=Creepster&display=swap
该项目的负责人 表示 缓存是这个问题(尽管有人反驳了,因为他们已经支持任意文本参数)。
添加查询参数会减少跨站点缓存命中率。如果我们最终为 font-display 获取一些东西,再加上一大堆用于可变字体的参数,那么这可能会给我们带来问题。
他们在主题的后面再次提到这一点,因此听起来我们不太可能很快获得查询参数,但我希望自己错了。
选项:下载并自行托管它们
所有 Google Fonts 都是开源的,因此我们可以获取它们的副本,以供我们想要使用的任何用途。

一旦字体文件自行托管并提供,我们实际上就是在编写 @font-face
块来自己链接它们,并且我们可以自由地包含我们想要的任何 font-display
。
选项:获取并更改
Robin Richtsfeld 提出了一种想法,即从 JavaScript 中运行一个 Ajax 调用来获取字体,然后更改响应以包含 font-display
并将其注入。
const loadFont = (url) => {
// the 'fetch' equivalent has caching issues
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onreadystatechange = () => {
if (xhr.readyState == 4 && xhr.status == 200) {
let css = xhr.responseText;
css = css.replace(/}/g, 'font-display: swap; }');
const head = document.getElementsByTagName('head')[0];
const style = document.createElement('style');
style.appendChild(document.createTextNode(css));
head.appendChild(style);
}
};
xhr.send();
}
loadFont('https://fonts.googleapis.com/css?family=Rammetto+One');
很聪明! 不过,我不确定这如何融入字体加载的世界。由于我们现在正在 JavaScript 中处理此字体的加载,因此加载性能与我们加载运行此代码的脚本的时间和方式相关联。如果我们要这样做,也许我们应该考虑使用官方的 webfontloader?
选项:服务工作者
与上面类似,我们可以获取字体并对其进行更改,但可以在服务工作者级别执行此操作,以便我们可以将其缓存(也许效率更高)。Adam Lane 写了这篇
self.addEventListener("fetch", event => {
event.respondWith(handleRequest(event))
});
async function handleRequest(event) {
const response = await fetch(event.request);
if (event.request.url.indexOf("https://fonts.googleapis.com/css") === 0 && response.status < 400) {
// Assuming you have a specific cache name setup
const cache = await caches.open("google-fonts-stylesheets");
const cacheResponse = await cache.match(event.request);
if (cacheResponse) {
return cacheResponse;
}
const css = await response.text();
const patched = css.replace(/}/g, "font-display: swap; }");
const newResponse = new Response(patched, {headers: response.headers});
cache.put(event.request, newResponse.clone());
return newResponse;
}
return response;
}
甚至 Google 也同意使用服务工作者来帮助 Google Fonts 是一个好主意。 Workbox(他们用于抽象服务工作者管理的库)使用 Google Fonts 作为主页上的第一个演示
// Cache the Google Fonts stylesheets with a stale while revalidate strategy.
workbox.routing.registerRoute(
/^https:\/\/fonts\.googleapis\.com/,
workbox.strategies.staleWhileRevalidate({
cacheName: 'google-fonts-stylesheets',
}),
);
// Cache the Google Fonts webfont files with a cache first strategy for 1 year.
workbox.routing.registerRoute(
/^https:\/\/fonts\.gstatic\.com/,
workbox.strategies.cacheFirst({
cacheName: 'google-fonts-webfonts',
plugins: [
new workbox.cacheableResponse.Plugin({
statuses: [0, 200],
}),
new workbox.expiration.Plugin({
maxAgeSeconds: 60 * 60 * 24 * 365,
}),
],
}),
);
选项:Cloudflare Workers
Pier-Luc Gendreau 研究了 使用 Cloudflare Workers 来处理这个问题,然后跟进 使用 Cloudflare 和服务工作者增强 Google Fonts,显然性能更好。
@font-feature-values
选项:等待 Google 可能对此拖延不决的原因之一(他们也说过同样的话)是,有一个名为 @font-feature-values
的新 CSS @rule
,它专门为这种情况而设计。 这是规范:
此机制可用于为整个字体系列设置默认显示策略,并使开发人员能够为不受其直接控制的
@font-face
规则设置显示策略。例如,当第三方字体铸造厂提供字体时,开发人员无法控制@font-face
规则,但仍然能够为提供的字体系列设置默认字体显示策略。能够为整个字体系列设置默认策略对于避免赎金字形效果(即不匹配的字体字形)也很有用,因为显示策略随后将应用于整个字体系列。
这太有趣了,因为这是我最近一直在努力解决的问题!
我最终使用 FontFaceObserver (https://github.com/bramstein/fontfaceobserver),到目前为止它对我来说非常有效,尤其是在添加一个有趣的 cookie 来检查用户是否为之前访问者时(如果是,则应用“fonts-loaded”的类并使用缓存的字体 - 否则,不应用类,使用备用字体,然后 FFO 等待 GFonts 下载,然后更改(因此 FOUT)。类似于:https://www.filamentgroup.com/lab/font-events.html
我使用服务工作者,因此我真的很想看看与 FFO 相比的性能优势和易用性(可能节省了几 KB/几次请求?)
您是否有使用 FFO 的经验?
当我获得 96(或 97)的性能和最佳实践分数时,我差点哭出来,唯一剩下的就是我无法做到的事情。我可能会选择 SW 缓存,希望能获得 100/100 的完美分数。
这将有所帮助:https://google-webfonts-helper.herokuapp.com/fonts
对于任何想要实现 font-display 的人来说,这是一个极好的信息。希望谷歌能尽快实现这一点,因为正如你提到的,洞察会发出警报,这样它应该向后兼容。干杯!
大家好,这里有一个(希望)更方便的方法来处理这个问题。你只需要从例如 https://fonts.googleapis.com/css?family=Creepster 下载 CSS 文件,然后在其中添加你自己的规则。因为你将使用 @font-face 选项控制,同时从谷歌的快速服务器加载字体。希望这有帮助!
Fonts API 为发起请求的特定用户代理提供一个生成的样式表。
如果你下载了 CSS 文件,你会得到一个适用于你用来下载的任何用户代理的样式表版本,然后将该样式表提供给所有用户代理。
请查看这里
https://developers.google.com/fonts/docs/technical_considerations
是我还是每个人都遇到了服务工作不正常的问题?服务工作无法读取请求的内容(text() 返回空字符串)。我猜这是为了安全原因而被阻止的,防止服务工作从不同域名读取响应。
http://fonts.googleapis.com/css?family=Creepster&font-display=swap
这个不再起作用了
嘿 Lukas!这就是这篇文章指出的内容——拥有这种参数会很棒,但我们还没有,不过我们希望有一天能拥有它。:)
哦,我以为它以前是可行的,抱歉:)
我的解决方案是创建一个简单的 php 文件,它将所需的 css 从
fonts.googleapis.com
下载到一个变量中,在每个@font-face {
行之后插入font-display: ...
行,然后返回内容。要获取的准确的 Google 字体 url 可以作为查询参数传递。然后将所有https://fonts.googleapis.com/css?family=...
引用替换为htt*://yourdomain/google-font.php?family=...
。完成。没有 JavaScript 延迟,没有更多库或魔法。由于修改后的 css 中的引用仍然指向 Google 服务器,因此站点可以从之前缓存的字体中获益,即使其他使用相同字体的站点也一样,这比自托管字体文件更好。