5步优化web字体
本文原文出处:https://iainbean.com/posts/2021/5-steps-to-faster-web-fonts/ ,我进行了翻译和归纳整理。
在这篇文章中,我将介绍5种提示web字体性能的方法。
# 1.使用最现代的字体格式
WOFF2是目前最小、最高效的web字体格式。在CSS文件中使用@font-face
的时候,得确保WOFF2字体在TTF这样的老格式前面。浏览器会默认使用最先声明的字体。
@font-face {
font-family: 'Typefesse';
src: url('typefesse.woff2') format('woff2'),
url('typefesse.woff') format('woff');
}
除非需要支持IE8,WOFF2和WOFF完全可以满足一切需求。如果连IE11都不用支持,WOFF2就够了。
如果手上只有TTF文件,可以用Online Font Converter来进行转换。
# 2.使用font-display
属性
以下是两种字体载入策略:
- FOIT(Flash of *Invisible* Text)是浏览器下载完毕相应字体前,文本不可见
- FOUT(Flash of *Unstyled* Text)是浏览器下载完毕相应字体前,文本使用后备字体渲染
这两种策略都不是完美的。如果使用自定义字体,其中的一种可能会在用户初次访问时出现(之后的载入浏览器基本都会从缓存中加载字体)。如果在之前的@font-face
代码中插入font-display
属性,可以指定我们想要的策略。
@font-face {
font-family: 'Typefesse';
src: url('typefesse.woff2') format('woff2'),
url('typefesse.woff') format('woff');
font-display: swap;
}
font-display
属性有五种可行值:
# auto
auto
是浏览器默认的值(大多数浏览器倾向于FOIT)。
# swap
swap
告诉浏览器我们想在自定义字体加载完毕前使用后备(fallback)字体渲染文本(也就是FOUT)。不管花了多少时间加载自定义字体,只要加载完毕,文本马上就会切换到该字体。这允许用户直接开始阅读文本,但要确保后备(fallback)字体不要和自定义字体差别太大,不然在切换时会导致较大的布局变化。
# block
如果我们更倾向于让浏览器在字体载入完毕前隐藏文本(即FOIT),我们可以使用font-display:block
。文本不会永远隐藏,如果自定义字体没有在特定时间内(通常是3秒),浏览器会自动使用后备(fallback)字体,但在自定义字体载入后,会自动切换。
如果你感觉FOUT策略视觉效果不好,这是最佳的选择。但是得记得,一开始文本不可见的时候,你的页面对于用户来说不可读的。
# fallback
fallback
和swap
很像,有以下两个区别:
- 开始时有一个很短的(约等于100ms)的空白时间,此时文本被隐藏,然后显示后备(fallback)字体。
- 如果自定义字体没有在短时间内载入(约3s),后备字体会一直使用下去,不会再切换。
如果不在乎用户是不是能在第一次载入网站时看到自定义字体,fallback
是一个好的选择。
# optional
optional
和fallback
很像。它给字体一个很短的时间(约100ms)加载,如果超时则不再会切换字体。然而,它还有一个额外的特性——允许浏览器决定在字体加载速度过慢时,放弃字体的加载。
每个页面上的字体都会有自己的FOIT/FOUT策略,他们在自己加载完毕后执行切换,而不是所有字体都加载完毕才切换。这回导致一些特殊行为(参见the Mitt Romney Web Font Problem)。为了对字体加载策略的完全掌控,需要使用JS来解决。
# 3.预载入字体文件
为了减小FOIT/FOUT的时间,自定义字体的载入得尽可能更快一点。在<head>
标签中使用link rel="preload"
可以告诉浏览器提前载入字体。在<head>
标签前(在所有CSS前)添加如下代码,并给你的字体设置href
属性:
<link rel="preload" href="/typefesse.woff2" as="font" type="font/woff2" crossorigin>
通过添加这个标签,浏览器加载时会立刻载入字体文件,而不是在它找到CSS中对该字体的引用和使用它的DOM元素时才开始载入。
浏览器通常只会下载当前页面需要的字体。可以使用preload
(预载入)来覆盖这一行为,强制浏览器下载未被使用的字体。这会带来更高的加载成本,因此,每个字体都应该只被preload
(预载入)一种字体格式(如果有WOFF2的话,就用WOFF2)。
越多字体被preload
(预载入),这篇文章描述的优化方法收益越低。因此,优先加载用户不需要滚动页面就可以看到的字体(100vh)。
可以在这里看到更多关于预载入的文章:Preload: What Is It Good For?
# 4.创建字体文件的子集
通过创建字体子集,可以生成一个更小的字体文件,只包含我们需要的字形(独立的字符和符号)。可以使用Everything Fonts上的Font Subsetter来生成字体子集。这可以大大降低字体文件的大小。
字体子集化是一个非常有效方法,但是这可能也会带来一些缺点。如果你正在开发一个呈现用户自己创建的内容的网站,就需要注意用户可能会输入任何子集化可能已经被排除的字符。
# 5.把字体托管在自己的主机上
这一步和上面四步不同,这不是通用的方法。直接使用Google Fonts或Adobe Fonts而不是自己主机上托管字体的原因有两个:
- 他们是获得特定的字体最便宜或者唯一合法的途径。
- 他们很方便——比起下载字体文件,转换、生成子集,编写
font-face
,字体托管服务直接复制粘贴HTML代码就可以引入字体。
如果你纯粹是为了方便使用Google Fonts,可以试试google-webfonts-helper。这个工具能帮你一键下载所需的字体文件和CSS代码。
你可能听说过,如果一个用户之前访问过网站,浏览器不会再下载从之前一样的源获取的一样的字体,因为它们被缓存了。
这可能是真的,但是我没发现这个机制肉眼可见地生效来改进载入速度。事实上,为了避免跟踪,Chrome和Safari都明确阻止来自其他域的第三方资源进行缓存
这是把字体托管在自己的主机上的好处:
# 性能
解析域名需要时间。你可以使用[预连接]( resource hints)技术减轻这个问题,但开启一个新的TCP连接肯定会有性能问题。这可能就是Google一些自己的网站现在都使用自己托管的字体的原因。
# 隐私
有偿的字体服务商(如Adobe Fonts)为了计费的需求,需要检测页面内容,但是他们可能会收集更多不必要的信息。如果可以,在CSS中加载字体(<link rel="stylesheet">
)而不是在javaScript中(<script>
),这样减少第三方获取你用户的信息数据量。
# 控制
自己托管字体当然可以获得完全的控制权限。你可以指定字体载入方式,创建子集,声明font-display
设置,指定浏览器缓存字体文件的时间。
# 可靠
第三方服务可能会面临减速、下线等问题。自己托管字体的好处是只要网站能运行,字体肯定也可以。
# 总结
每个方法都有自己的优点,结合起来可以带来巨大的提示。如果你决定实现一些文章中提到的方法,可以用Lighthouse或Web Page Test在你修改前后进行测试,看看每个方法带来的效果。