Remember FOUT? When using a custom font via @font-face, browsers used to display a fallback font in the font stack until the custom one loaded. This created a "Flash of Unstyled Text" — which was unsettling and could cause layout shifts. We worked on techniques for fighting it, for instance, making the text invisible until the font was ready.
\A number of years ago, browsers started to shift their handling of this. They started to detect if text was set in a custom font that hasn't loaded yet, and made it invisible until the font did load (or X seconds had passed). That's FOIT: "Flash of Invisible Text". Should a font asset fail or take a long time, those X seconds are too long for people rightfully concerned about render time performance. At worst, this behavior can lead to permanently invisible content.
问题
先来看一下 FOIT(Flash of Invisible Text) 的表现(GitHub 只会播放一次 GIF,拖到一个新窗口刷新可重放):
简单来说 FOIT 就是文字使用了自定义的 font-face,所以导致在自定义的字体加载完毕在之前,对应的文字会显示一片空白。 在老版本的浏览器中,会优先显示 font-family 中已经可以显示的候选字体,然后当 font-face 的字体加载完毕后,再变成 font-face 的字体,这被称作 FOUT(Flash of Unstyled Text)
下面是对 FOUT 和 FOIT 的一段英文解释,比较全面:
之所以从 FOUT 变成 FOIT,就是在字体变更的时候会因此 re-flow,而 re-flow 的代价是很大的,所以干脆就直接不显示,在 font-face 载入后再显示。
目的
在实际的工程中,我们可能有几种对于 font-face 加载的需求:
解决
1. 使用
font-display
来实现 FOUTfont-display: swap
:浏览器会直接使用 font-family 中最先匹配到的已经能够使用的字体,然后当font-family
中更靠前的字体成功载入时,切换到更靠前的字体,相当于是 FOUT。font-display: fallback
:浏览器会先等待最靠前的字体加载,如果没加载到就不显示任何东西,这个过程大约持续 100ms,然后按照顺序显示已经成功载入的字体。在此之后有大约 3s 的时间来提供切换到加载完毕的更靠前的字体。font-display: optional
:浏览器会先等待最靠前的字体加载,如果没加载到就不显示任何东西,这个过程大约持续 100ms,然后字体就不会再更改了(一般第一次打开某页面的时候都会使用 fallabck 字体,字体被下载但是没被使用,之后打开时会使用缓存中的字体)。2. 使用 Web Font Loader
使用 JS 而不是 CSS 来引入字体,WFL 会在字体引入的整个过程提供多个钩子函数,具体可以参考 官方文档 和 Loading Web Fonts with the Web Font Loader
举个小例子,比如我想让某标题使用 font-face 字体。载入页面后,标题一开始是不可见的,直到自定义字体被成功加载后标题才向上浮动显示,当超过 5s 还没成功载入字体时将按 fallback 字体显示。这就需要判断自定义字体什么时候成功加载,什么时候载入失败。
Tips
还有一些关于 font-face 的知识我们也必须了解
参考