字体加载策略大全
本指南不针对于具有优先级加载以及用例示范的font icons,或许,SVG会是一个更好地长期选择。
快速指南
如果你正在寻找具体的方法,这里的一些相关链接可能对你的帮助会更加直接。比方说:
- 最全面的方法,对大多数用例都有帮助的,具有class的FOUT。
- 最容易实现的: 我学习了很多关于Web字体的知识。写这篇文章时,浏览器对Web字体的实现缺少最简单有效的方法。如果你想要寻找最简单有效的方法,那么你就需要考虑放弃使用Web字体了。如果你不了解Web字体是如何改善你的设计的,那么你可能也不适合使用Web字体。这里请不要误会我的意思,Web字体还是十分有用的。但是,请正确使用它,以便将它的作用发挥到极致(这里我所了解到的,Robin Rendle对Web字体的使用价值有深刻的研究)。
- 绩效导向最好的方法: 使用一种Critical FOFT的方法。就我个人而言,我的偏好是使用具有Data URI的Critical FOFT。但是,如果浏览器支持
preload
,我会转向使用具有preload
的Critical URI。 - 使用大量的Web字体: 如果你痴迷于Web字体(使用超过4~5种Web字体或者总文件大小超过100KB),这就会有一点棘手。我会首先建议你减少Web字体的使用,但是如果不可以坚持一种标准的FOFT,或者是具有两种渲染状态的FOUT,请为每种字体使用单独的FOFT(Roman,Bold,Italic等进行区分)。
- 使用现有的云/Web字体托管: FOFT方法一般需要自托管,所以坚持尝试并使用具有class的FOUT。
标准
- 易于实现: 有时,简易就是最好的选择。
- 渲染性能: FOUT具有一种特征,允许你立即呈现回调的字体以及在加载时呈现Web字体。我们可以采取措施减少回调字体显示所需的时间,减少甚至完全消除FOUT的影响。
- 可扩展性: 一些字体加载需要Web字体加载所需的一系列方法。我们想要这个需求平行出现。对每种方法所需的Web字体开支进行预算。
- 未来友好性: 当出现一种新的字体格式,是否需要更多的研究以及维护,或者说是否可以很容易适应?
- 浏览器支持: 是否拥有足够广泛的基础,可满足大多数项目的浏览器需求?
- 灵活性: 该方法是否便于对Web字体需求进行分组以及与它们相关的重绘与回流?我们希望可以对Web字体加载类型以及加载时间进行控制。
- 稳定性: 如果Web字体请求被挂起会发生什么?文本不可读还是Web字体将会变为一个单独的点(SPOF)?
- 托管: 该方法是否需要自我托管或者适应于各种Web字体加载程序提供的云供应商/字体铸造厂?
- 子集: 一些字体证书不允许有子集。下面的一些方法需要子集才可以获取最佳性能。
@FONT-FACE
将一个赤裸裸的@font-face
块放置于页面之中并抱有最好的希望。这是Google Fonts建议的默认方法。
优点
- 十分简单: 使用WOFF以及WOFF2(可能也存在OpenType格式,如果想支持4.4以下格式的Android--将WOFF与TTF/OTF进行比较,择优使用)格式添加一个CSS
@font-face
块。 - 未来友好性: 默认的Web字体行为。这是Web字体的主流,当然添加额外的字体格式也十分简易,用逗号进行分隔,在
src
中添加另外一个@font-face
的URL。 - 在Internet Explorer和Edge中具有良好的渲染性能: 没有FOIT,没有隐藏的或者不可见的文本。我完全支持Microsoft的设计理念。
- 不需要修改字体(通过子集或者其他方式)。非常友好的许可证明。
缺点
- 不好的渲染性能: 大多数现代浏览器中最多三秒FOIT,如果负载时间过长,切换到FOUT。若请求提前完成,三秒内看不到可读内容,我们就会产生网络不可靠性的理念。
- 不稳健性: 一些Webkits不具有最大的FOIT信息(尽管Webkit近期已经修复了这一点,但是Safari 版本10仍存在此问题),这意味着Web字体请求将会出现故障(如果请求挂起,内容将不会显示)。
- 进行请求分组或者统一重绘不方便。每一种Web字体都会产生重绘或者回流,并具有自己的FOIT/FOUT超时信息。这将会产生像Mitt Romney不良的web字体问题。
个人意见: 不建议使用。
FONT-DISPLAY
在@font-face
块上添加一个新的,可选择的,并且浏览器支持的FOUTfont-display: swap
描述符。如果你感觉Web字体对于设计不是必需的,那么就可以设置font-display: fallback
或者font-display: optional
。书写文章时,此功能在任何稳定的浏览器中均不可用。
扩展阅读
优点
- 十分简便: 仅仅需要在你的
@font-face
块上添加一个单一的CSS描述符。 - 良好的渲染性能: 如果所有的浏览器对其均支持,可以不使用JavaScript就提供给我们FOUT。通过CSS来实现是最佳的方法。
- 超级的未来友好性: 正交到Web字体格式。如果向你的栈中添加新的格式,不需要进行相关修改。
- 非常稳健: 即使Web请求挂起,在所支持的浏览器中也会显示回调信息。如果Web字体不依赖于JavaScript polyfill会更好,因为即使JavaScript加载失败,用户仍旧可以访问Web字体。
- 不需要修改字体(通过子集或者其他方式)。具有良好的许可性。
缺点
- 不具有稳定的浏览器支持。只有Chrome平台对其有一个状态支持。在Firefox平台以及Edge平台还没有被记录。只有得到所有A级浏览器的支持,否则,开发人员仍旧需要使用JavaScript方法。
- 有限的灵活性: 无法对请求或者重绘进行分组。也不是那么糟糕 -- 如果你FOUT一切,你将避免Mitt Romney Web字体问题,但是另一方面,分组又十分有用,我们接下来会进行讲解。
- 托管: 任何已知的Web字体托管均没有对此属性的控制。如,Google Fonts CSS。当浏览器的支持有所改善时,可能会有所变化。
个人意见: 使用既无益也无害
PRELOAD
添加<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>
快速获取字体。可以很好的阻止@font-face
,并且可以通过font-display
进行显示。
扩展阅读
请记住: 这种方法的缺点与优点很大程度上依赖于你字体的加载策略,不论是
@fongt-face
还是font-display
。
优点
- 超级容易实现,仅仅需要一个
<link>
。 - 比
@font-face
更好的渲染性能。Web字体在瀑布流中要求会更高。 - 使用
type
属性指定的字体格式,将具有良好的未来友好性。基于这一点,Web浏览器在WOFF2实现预preload还是可能的(虽然看起来不大可能),没有这个属性的话,将产生一个没有用的请求。所以,确保你包含了这个type
。 - 不需要修改字体(通过子集或者其他方式)。具有良好的许可性。
缺点
- 可扩展性: 预加载越多,阻止的初始渲染越多(注意,这种比较获取的数据网站使用的是Critical CSS)。尝试使用最重要的一个或两个Web字体。
- 有限的浏览器支持 - 目前仅仅Blink支持,但是可能不久就会得到更多的支持。
- 灵活性: 无法对重绘/回流进行分组。
- 可能没有办法使用第三方托管。你需要知道正在请求Web字体所标记渲染的URL,如,Google Fonts,在CDN中生成这些CSS请求。
个人意见: 本身不足以使用
不要使用Web Fonts
我不会对这种方法讲述太多,这只不过是一种字体加载策略。但是,相较于错误使用web字体,这种方法的作用将会更好。你会错失很多新的排版功能以及web字体的可读性改进,但是最终决定权在你。
优点
- 不能确定是否简便: 只使用
font-family
不使用@font-face
。 - 周边即时的渲染功能: 不用担心FOUT或者FOIT。
缺点
- 有限的可用性。很少的系统字体可跨平台。检查fontfamily.io,看看具有浏览器支持的系统字体是否满足你的需求。
个人意见: 猜测可以实现,但是我不会对其感兴趣。
内联 Data URI
通常有两种类型的内联方法: 阻止<link rel="stylesheet">
请求或者服务器在<style>
元素内渲染标记。alibaba.com(在阻塞的CSS请求中嵌入了两种Web字体)以及medium.com(七种Web字体)使用此方法。
扩展阅读
优点
- 表面看起来很棒的渲染性能: 这种方法没有FOUT或者FOIT,是存在的一个很大的问题。
- 灵活性: 不需要担心对重绘/回流进行分组,这种方法不存在FOUT或者FOIT。
- 稳定性: 内联请求将放置在初始化的服务器中。
缺点
- 渲染性能: 尽管这种方法没有FOUT,但是可以显著延迟渲染时间。另一方面,它会呈现“finished”。需要记住,单一的WOFF2 Web字体大小也接近于10KB-15KB。inline Data URI传到HTTP/1仅仅需要14KB或者说是更小的临界渲染路径。
- 浏览器支持: 在
@font-face
块中不能使用逗号进行格式列表的分隔,这种方法只可以嵌入一种格式类型。一般为WOFF,所以使用这种方法一定情况下,强迫你在ubiquity(WOFF)以及用户代理支持的比较狭隘的,文件较小的(WOFF2)之间进行选择。 - 较差的可扩展性: 请求发生不平行,以串行方式加载。
- 自我托管: 貌似是必然结果。
个人意见: 忽略FOUT,你可以使用这种方法,但是我不推荐使用。
异步数据URI样式表
使用工具,如loadCSS,获取作为Data URIs嵌入的的所有数据的样式表。你会经常看到用户代理为了重复显示,在存储样式表时使用了一种localStorage
的方法。
扩展阅读
优点
- 渲染性能: 消除了大部分的FOIT(参考以下列出的缺点)。
- 灵活性: 容易将请求进行分组,产生单一的重绘(在一个样式表放置多个Data URIs)。
- 方便: 不需要添加额外的CSS。这是一种很大的好处。但是,实现效果并不总是令人如意。
- 稳定性: 如果异步请求失败,回调文本将会正常显示。
缺点
- 渲染性能: 比较明显,但是解析样式表以及数据URIs时,会存在短暂的FOIT。这相当令人分心。我经常看到这种方法的使用,以至于不用去看源代码就可以识别出来。
- 灵活性以及可扩展性: 分组请求与重绘耦合在一起。如果你对多行Data URIs进行分组(这会导致连续以及不平行的加载),他们会被一起重绘。使用这种方法,你不能平行加载,也不能对重绘进行分组。
- 不良好的维护性。要求要有自己的方法来确定字体格式的支持。你的JavaScript加载程序将决定在读取数据URI样式表之前支持哪种字体格式(WOFF2或者WOFF)。意味着当出现一种新的字体格式时,你需要对其进行一个开发测试。
- 浏览器支持: 你可以直接跳过加载程序步骤的维护以及到WOFF2或者WOFF的硬编码,但是这可能会导致更大的或者可能的一次性请求(与我们谈到的Inline Data URIs的缺点相同)。
- 自我托管: 需要。
个人意见: 其实还好,但是我们可以选择更好的。
具有类名的FOUT
当加载一种特定字体时,使用具有polyfill的CSS Font Loading API进行检测,并且只在你的CSS完全成功加载后才使用该Web字体。一般情况下,意味着在<html>
元素上进行类的切换。使用SASS或者LESS minins会更容易进行维护。
扩展阅读
优点
- 性能渲染: 消除了FOIT。这种方法已经经过检测与测试,也是TypeKit所推荐的方法之一。
- 灵活性: 方便对请求进行分组,实现单一的重绘(为多行web字体加载使用单一类)
- 可扩展性: 请求平行出现
- 稳定性: 若请求失败,回调文本依旧会呈现。
- 托管: 字体加载程序独立(使用第三方托管容易实现或者使用已经存在的
@font-face
块) - 良好的浏览器支持,通常Web字体被支持的地方都是polyfills在起作用。
- 未来友好性: polyfills与字体格式不耦合,与现有的
@font-face
块一起工作。这就意味着当出现一种新的格式时,你可以正常修改你的@font-face
。 - 不需要修改字体(通过子集或者其他方式)。具有良好的许可性。
缺点
- 需要对你的CSS进行严格的维护/控制。在你的CSS中单一使用Web字体
font-family
,没有防卫性的loaded
类的加载会触发FOIT。 - 当你想要在页面加载web字体时,需要进行硬编码。意味着,你结束了网页所需的Web字体内容的加载。另外,对于
@font-face
唐突的使用,新的浏览器只会下载页面所需的字体。这就是为什么New York Times可以在首页获取100多种不同的@font-face块,但是浏览器只是下载其中的一小部分。使用此方法,你必须告知浏览器需要独立下载哪些方法。
个人意见: 基线标准,大多数情况下适用。
FOFT, OR FOUT WITH TWO STAGE RENDER
这种方法基于具有一个类方法的FOUT,当你加载具有多个权重或者样式相同的字体时会更加有用,如: Roman,Bold,Italic,Bold Italic, Book, Heavy等等。我们将这些Web字体分为两个阶段: 首先为Roman,因为当加载真正字体的可选样式时,它会立即渲染faux-bold
以及faux-italic
内容(使用字体合成)。
扩展阅读
优点
- 具有一个类方法的FOFT所拥有的全部优点
- 渲染性能: Web字体加载时,大大降低了跳转内容的数量。将我们的Web字体加载分为两个阶段,如果我们将所有的字体进行分组,产生单一的重绘,这使得第一阶段(Roman font - 会产生大部分的回流)将会加快。
缺点
- 具有一个类方法的FOFT所拥有的全部缺点。
- 一些设计师对字体的合成高度敏感。客观的说,合成的变化地作用远远不如真实表现的,但是这也不存在一个公平的比较。记住,合成的版本一般都是一个临时的占位符,我们需要时刻保持疑问: 他们是不是比回调字体更具有优势或者劣势?答案有很多。
个人意见: 对额外的性能感兴趣,但是不具有Critical FOFT的子集。
CRITICAL FOFT
这种方法与FOFT之间的唯一区别在于,第一阶段我们不是嵌入所有的Roman web字体,而只是其中一个子集(通常仅仅包含A-Z以及可选的0-9/或者标点)。在第二阶段,加载所有的Roman web字体以及相关样式。
扩展阅读
优点
- FOFT所拥有的全部优点。
- 渲染性能: 第一阶段的加载会更快(网速较慢时会更加明显),进一步减少了第一阶段Web字体的重绘时间,将会导致你正常使用的Web字体的回流会提前。
缺点
- FOFT所拥有的全部缺点。
- 在第一阶段加载Roman web字体的子集,第二阶段加载全部Roman web字体,这是减少回流而付出的代价。
- 许可限制: 要求子集。
个人建议:使用下面改进的FOFT。
使用Data URI的CRITICAL FOFT
Critical FOFT方法只是改变第一阶段的加载机制。不使用正常的JavaScript API字体加载来启动下载,而是直接在标记中嵌入文字作为内联Data URI。如前所述,这会阻止初始渲染,但是我们只是嵌入比较小的Roman web字体的子集以消除FOUT,这种代价还是比较小的。
扩展阅读
优点
- Critical FOFT所拥有的全部优点。
- 消除了FOIT,并且使用Roman字体减少了FOUT。在第二阶段添加额外字符,或者加载其它样式时会产生小的回流,但是这种影响相对较小。
缺点
- Critical FOFT方法所具有的所有缺点。
- 小的内联Data URI将会轻微阻止初始渲染。我们使用只是为了减少FOUT。
- 自我托管: 需要。
个人意见: 在我看来,这是目前最好的黄金法则。
使用 PRELOAD的CRITICAL FOFT
Critical FOFT方法只是改变第一阶段加载的机制。不使用正常的JavaScript API字体加载来启动下载,我们使用如上文所述的新的preload
Web标准方法。相较于正常方法,这种方法将会提前触发下载。
扩展阅读
优点
- Critical FOFT所拥有的全部优点。
- 渲染性能: 相较于以往方法,在瀑布流中下载提前被触发。我猜测使用HTTP标头会产生更加戏剧性的效果,但是目前还没有被证实。这种方法优于使用Data URI的Critical FOFT,因为它可以使用缓存进行重复请求,而不是使用每一种服务器标记重复获取相同的web字体数据。
缺点
- Critical FOFT方法所具有的所有缺点。
- 只使用单一的Web字体格式。
- 如上所述,浏览器的有限支持 - 书写这篇文章时,只有Blink对其支持。
- 预加载可以稍微延迟初始渲染(这种对比数据收集的网站使用的是Critical CSS)
- 自我托管:可能需要。
个人建议: 如果浏览器支持,这将是最佳选择方案
本文根据@zachleat的《A COMPREHENSIVE GUIDE TO FONT LOADING STRATEGIES》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:https://www.zachleat.com/web/comprehensive-webfonts。
如需转载,烦请注明出处:https://www.fedev.cn/css/comprehensive-webfonts.htmlNike MagistaX Proximo II TF white Fluorescent yellow women football shoes