本文讲的是字体加载策略全面指南,

2016 年 7 月 12 日, 本文需要 20 分钟的阅读时间。

这份指南并不是教你怎么使用显示图标字体,它有不同的加载优先顺序和使用场景。事实上,此时使用 SVG 或许才是一个长久之计。

跳转到:

  • 随意使用 @font-face
  • font-display
  • 预加载 preload
  • 不要使用在线字体
  • 内嵌数据 URI
  • 异步数据 URI 样式表
  • 有分类的 FOUT
  • 两个阶段渲染的 FOFT,或 FOUT
  • 严格的 FOFT
  • 有数据 URI 的严格 FOFT
  • 有预加载 preload 的严格FOFT

快速指南

我想要一个这样的实现途径:

  • 是一个对大多数使用场景来说足够好且全面的实现方式: (例如) 有分类的 FOUT

  • 是尽可能最容易实现的方式: 我已经学习了很多有关 在线字体 (的知识),在我写这篇文章的时候,目前的浏览器还缺少对在线字体高效,稳定和最容易的实现方案。不得不承认,如果你正在寻找现存的可行方案,请考虑 不要使用在线字体。如果你都不清楚在线字体能为你的设计带来什么提升的话,他们确实一点儿都不适合你。别误会,在线字体是一个伟大发明。但是你得让自己明白什么是它能带来的好处。( 由Robin Rendel创作的,为在线字体辩护,论_在线字体的价值_ 是一个让你初步了解在线字体的好文章. 如果你还知道其他的, 请留言告诉我.)

  • 是一个有最佳性能的实现方式: 使用 严格的 FOFT 实现方式其中的一个。就个人而言,在我写作的时候,我个人偏爱 有数据 URI 的严格 FOFT, 但是仍转向了 有预加载 preload 的严格FOFT,因为越来越多的浏览器支持preload(预加载)功能。

  • 能和大量的在线字体(库)很好的配合工作: 如果你痴迷于在线字体(任何多过 4 或 5 个的在线字体或者总共文件大小多于 100KB)这有点复杂。我先推荐你尝试削减你的在线字体的使用量,但如果这不可能保持标准 两个阶段渲染的 FOFT,或 FOUT 的实现方式。为每一个字型使用不同的 FOFT 实现方式(RomanBoldItalic 等等分类)。

  • 将能和我现存的云/在线字体的托管服务解决方案配合使用FOFT 的实现方式一般来说需要亲自托管服务, 所以保持可靠和真的 有分类的 FOUT 的实现方式.

标准

  1. 简化实现: 有时候, 简单才能赶上最后的时间期限。
  2. 渲染性能: FOUT 的特性是允许立刻渲染回退方案的字体也可以渲染在线字体,当它完成加载时。我们可以采用额外的步骤减少大量的显示回退方案字体的时间并且减少了对 FOUT 的影响, 更有甚者能将他们一起消除。
  3. 可扩展性: 一些加载字体的实现方式支持连续的加载在线字体。我们想并行的执行这些请求。我们将评估每一个实现和扩张,发展中的在线字体配合度有多好。
  4. 拥抱未来: 如果有一个新的字体出现它将需要额外的研发和维护么, 或者它将能方便的适配么?
  5. 浏览器支持: 它是否能成功支持足够多的浏览器满足项目上的需要?
  6. 灵活性: 这个实现方式是否容易地促进整合在线字体的请求,重新绘制和(页面)回流? 我们想(完全)控制哪个字体何时(何地)被加载。
  7. 稳定性: 如果一个在线字体的请求被挂起了会发生什么呢?(需要被渲染的)文本将依旧被(显示)可读或者这个在线字体将是一个单点故障(SPOF)(导致整个字体渲染失败)?
  8. 托管服务: 这个实现方式是否需要亲自(虚拟主机)托管服务或者它是否能自适应配合多种多样的字体加载器(由其他云服务商/字体创始人提供)。
  9. 阉割版(裁剪版): 一些字体的(使用)许可证不允许(内容被)裁剪(需要保证完整性),然而有些实现方式不得不为了性能需要对字体(库)进行裁剪。

(Unceremonious) 随意使用 @font-face

随意把@font-face代码块放置在你的网页中并且希望这是最好的办法. 这是 Google Fonts 推荐的默认方式.

  • 演示程序: (Unceremonious)随意使用 @font-face

优点

  • 非常简单: 增加一个有 WOFF 和 WOFF2 格式的 CSS @font-face 代码块(也可以是 OpenType 格式, 如果你想要 Android 4.4 以下支持 - 比较下 WOFF 和 TTF/OTF)。
  • 拥抱未来: 这是浏览器默认的作法。这就是在线字体的主流形式。只需要在你的 @font-face 中, 在 src 属性中用逗号分割开其他需要包含的 URL , 就能增加额外的字体样式。
  • 在 IE 和 Edge (微软浏览器)上都有上佳的渲染性能: 没有 FOIT,没有被隐藏和不可见的文本。我完全支持微软这个英明的决定。
  • 不需要修改字体(通过裁剪或者其他形式)。 无需担心许可。

缺点

  • 在其他浏览器的渲染性能差强人意: 在多数其他流行的浏览器上最多有 3 秒时间的 FOIT, 切换到 FOUT 加载时间更长. 当然这些请求可能被更早完成, 尽管我们知道互联网(的响应时间)是会变得多么不可靠-但是对于内容至少 3 秒无法阅读, 这个时间还是太长了。
  • 目前来说, 不是很稳定: 一些基于 WebKit 内核实现的浏览器没有一个最大 FOIT 超时时间(虽然 WebKit 最近修复了这个问题并且我相信这个修复会被 Safari Version 10 采用。),这也意味着在线字体的请求会成为一个单点失败(如果这个请求被挂起, 那么内容将永远不会被显示)。
  • 将请求或重绘整合在一起一点都不容易。每一个在线字体都会引发一个单独的重绘/回流步骤和自己的 FOIT / FOUT 超时时间. 这会带来不良的情况, 例如 Mitt Romney 的在线字体问题 ).

结论: 不要使用。

font-display

在你的 @font-face 代码块中增加一个新的 font-display: swap 描述符选择性加入支持 FOUT 的浏览器。另外, 如果考虑到在线字体不是你设计一定需要的, 可以使用 font-display: fallback font-display: optional。在我写这篇文章时, 这个特性还没法在任何稳定的浏览器上使用。

优点

  • 非常简单: 只需要在你的 @font-face 代码块中增加一条 CSS 描述符号。
  • 上佳的渲染性能: 如果这个实现方式能被大部分的浏览器支持, 这将给我们一个没有任何JavaScript的 FOUT。 一个只有 CSS 的实现方式会更理想。
  • 超棒的拥抱(面向)未来: 与子线字体样式成正交状态。不需要改变什么, 你就可以在栈上增加新的字体。
  • 非常稳定: 即使在线字体的请求被挂起, 一种 FOUT 实现方式也将在浏览器中显示支持回退方案的文本。更好的是-你的在线字体并不依赖 JavaScript ployfill, 这意味着如果 JavaScript 方法失败, 用户依旧还能看到在线字体。
  • 不需要修改字体(通过裁剪或者其他形式)。无需担心许可.

缺点

  • 没有稳定的浏览器支持。只有 Chrome平台有一个更新状态。它没有被录入 Firefox 或者 Edge 平台。开发者门将可能需要匹配 JavcScript 实现方式, 直到一流的浏览器能支持。
  • 有限的灵活性: 没法整合请求和重绘。这也并没有听上去那么糟-如果你 FOUT 所有的东西你将避免发生 Mitt Romney 的在线字体问题, 但是整合在其他方面会很有用-我们将在之后讨论。
  • 托管服务: 没法在任何已知的在线字体托管服务中控制这个属性。这不在谷歌字体 CSS 中, 举例来说. 当浏览器支持以后, 这将会被改变。

结论: 但加无妨,但还是不够。

预加载 preload

增加 <link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin> 更快的获取到你的字体。配合@font-face 代码块使用并且也可以和 font-display 描述符号一起锦上添花。

切记: 这个实现方式的利弊完全取决于配合使用的加载策略, 无论是 随意使用 @font-face 或者 font-display

优点

  • 一键实现, 只需要一个 <link>
  • 比 @font-face 代码块更好的渲染性能,在线字体的请求优先级很高。
  • 拥抱未来, 如果你使用 type 属性去指定字体样式。在 WOFF2 之前, 一个网页浏览器扔可能执行 preload (虽然听上去不太会), 并且如果没有这个属性, 你可能会看到一个多余的请求。所以, 清确保包含了 type
  • 不需要修改字体(通过裁剪或者其他形式)。无需担心许可。

缺点

  • 可扩展性: 预加载的内容越多, 初始化渲染的内容就越容易被阻塞(注意, 从网站上获取的比对数据都使用了严格的 CSS)。 尝试仅仅使用 1 到 2 个重要的在线字体。
  • 有限的游览器支持 - 目前只有 Blink 支持, 但会越来越多。
  • 灵活性: 没法整合重绘/回流。
  • 这个实现方式你没法使用第三方的托管服务. 你需要在标记阶段提交你所请求的在线字体的 URL。 Google Fonts , 在 CSS 向他们的 CDN 请求的时候生成这些。

结论: 没有使用的必要。

不要使用在线字体

好吧, 其实我并不想讨论太多这个, 实际上这根本就不是一个技术上的加载策略。_但我必须说这比起滥用在线字体要好的多。_你正在错过很多在线字体能带给你新的字体特性和提升阅读性(的机会), 但这是你的选择。

优点

  • 不太确定哪个更加容易: 仅使用没有 @font-face 的 font-family
  • 几乎是即刻渲染: 不用担心 FOUT 或 FOIT

缺点

  • 可适用性很少。仅仅有少部分的字体支持跨平台。可查看 fontfamily.io 确认某个满足你需求的系统字体是否能被浏览器接受(支持)。

结论: 当然,可以使用。但我一点儿都不意外。

内嵌数据 URI

这个方法有两种嵌入式(的代码块): 一个是 <link rel="stylesheet"> 请求或在 <style> 在服务器渲染标记语言中。alibaba.com (在 CSS 请求中有两个在线字体)和 medium.com (7个在线字体)都使用了这个实现方式。

优点

  • 超棒的渲染性能: 没有 FOUT 或者 FOIT。 太了不起了!
  • 灵活性: 因为没有 FOUT 或 FOIT , 所以也就不必担心重绘和回流了。
  • 稳定性: 那些内嵌的代码将所有的事情放在了服务器初始化的请求中。

缺点

  • 一些渲染性能的缺陷: 虽然这个实现方式没有 FOUT ,但它将大大延迟初始化渲染的时间, 另一方面, 它将会"完成"渲染。但牢记即使是一个单独的 WOFF2 在线字体都差不多 10KB-15KB, 内嵌式只是一个数据 URI , 它将在严格的渲染过程中花费( HTTP/1 推荐值) 14KB 左右。
  • 浏览器支持: 没有利用在 @font-face 代码块中使用的以逗号分隔样式的列表: 这个实现方式仅内嵌一个样式类型。通常来说这就是 WOFF , 所以使用这个方法迫使你选择更有普遍性的 WOFF 或者更加少的支持但是更小的文件 WOFF2
  • 可扩展性差: 请求无法并行执行。只能逐条加载。
  • 亲自托管服务: 当然是必需!

结论: 仅在你无法容忍 FOUT 时使用该方法. 我个人不推荐用这个.

异步数据 URI 样式表

使用类似 loadCSS 的工具获取样式表, 所有的字体都嵌入在数据 URI 中。你也将竟然看到这个配合一个本地存储方法来把这个样式表存储在用户本地供其他视图重复使用。

优点

  • 渲染性能: 几乎可以消除FOIT (详见缺点)。
  • 灵活性: 方便的将请求整合到一个单独的重绘中(将多个数据 URI 放入到一个样式表)。
  • 容易性: 不需要其他额外的 CSS 的修改. 这是一个大大的好处, 然而, 实现的过程并不只有好处。
  • 稳定性: 如果异步请求失败了, 回退策略文本也将会被显示。

缺点

  • 渲染性能: 能被注意到, 但是非常短的 FOIT , 当样式表和数据 URI 被解析的时候。这有点碍事, 我都不用看源码都知道这个实现方式被使用了。
  • 灵活性和可扩展性: 整合的请求和重绘被结合在一起了。如果你也整合了多个数据 URI 到一起(这样造成都是顺序加载而非平行), 他们也将一起被重绘。通过这个方法, 你不可能再并行加载并且整合重绘。
  • 不太好维护. 你必须决定你支持哪些样式的字体。在获取数据 URI 数据样式表之前, 你的 JavaScripter 加载器将需要决定那种字体样式被支持(WOFF2 / WOFF). 如果有一个新的字体样式出现, 你将必须再为这个特性测试是否可行。
  • 浏览器支持(情况): 你可以采用硬编码 WOFF2/WOFF 去绕开加载器的持续维护工作, 但这势必引发更多的不需要的请求(相同的缺点我们已经在嵌入式数据 URI讨论过)。
  • 亲自托管服务: 必须。

结论: 这个可以,但是我们能做的更好。

有分类的 FOUT

使用 CSS 字体库中的加载API函数(polyfill)去检测当有某一个字体被加载时, 只将这个成功加载的在线字体应用到你的 CSS 中。同行这意味着放置一个开关类在你的 <span><html></span> 元素上。使用 SASS/LESS 进行更简单的维护操作。

优点

  • 渲染性能: 消除 FOIT。这个方法已经经过尝试和测试了。它也是 TypeKit推荐的一个实现方式.
  • 灵活性: 方便整个请求到一个重绘(可使用一个类处理多个在线字体的加载)。
  • 可扩展性: 并行执行请求。
  • 稳定性: 如果请求失败, 回退策略的文本也能被显示。
  • 托管服务: 可独立字体加载器功能(方便实现第三方的托管服务或现存的 @font-face 代码块)。
  • 最多的浏览器支持, polyfills 几乎能被所有的在线字体支持。
  • 拥抱未来: polyfills 并不一定和字体样式耦合, 它也能和现存的 @font-face 代码块工作。也就是当有一个心的样式出现, 你只需要一如既往的改变你的 @font-face 就可。
  • 不需要修改字体(通过裁剪或者其他形式). 无需担心许可。

缺点

  • 需要严格的维护和控制你的 CSS (代码). 单独使用在线字体集,且没有受保护的加载类, 可能会触发 FOIT
  • 一般都需要你硬编码(选择)哪个在线字体是你想要加载在网页上的。你需要加载多过一个网页需要的在线字体. 新的浏览器只会现在当前页面所需要的在线字体 @font-face 的实现方式。这就是为什么 纽约时报在他们的主页上侥幸逃过 100 个不同的 @font-face 代码块 - 浏览器只会下载一小部分。 通过这个方法, 你必须告诉浏览器哪个字体需要被下载, 与使用无关。

结论: 这是标准线. 被大部分情况使用。

两个阶段渲染的 FOFT, 或 FOUT

该实现基于 有分类的 FOUT 方法, 当你要对同一个字型加载不同的字体粗细和样的时候是非常有用的, 比如, Roman , Bold ,Italic , Bold Italic , BookHeavy 等等。 我们可以将在线字体分为两个阶段: Roman 优先, 之后将立即渲染faux-boldfaux-italic的内容( 使用字体合成), 然后真实的在线字体, 大权重和加载其他样式。

优点

  • 所有 有分类的 FOUT 方式的优点。
  • 渲染性能: 极大减少了当在线字体加载完成后内容发生的跳跃。考虑到我们把在线字体的加载分成两个阶段, 这允许第一步(Roman 字体 - 引发回流最多的)比我们把所有的字体整合到一个重绘更快。

缺点

  • 所有 有分类的 FOUT 存在的缺点。
  • 一些设计者讨厌字体合成. 客观来说, 合成的变化没有他们对应的有作用. 但这不是一个公平的比较. 牢记合成的版本知识一个临时性的替代物, 我们要问的是, 或多或少比回退策略的字体来的有用么? 答案是更多!

严格的 FOFT

这个方法和标准的 FOFT 实现方式不同的是, 在第一阶段不是完全的 Roman 在线字体, 我们使用 Roman 在线字体的一个子集(通常只会包含 A - Z 和 0 - 9 或标点符号)。 完全的 Roman 在线字体在第二阶段加载不同的权重和样式。

优点

  • 所有 FOFT 现存的优点。
  • 渲染性能: 第一阶段甚至加载的更快(特别在更慢的网络上更显著)更减少了第一阶段在线字体重绘的时间, 让你使用最多的在线字体更快的产生。

缺点

  • 所有 FOFT 现存的缺点。
  • 会引入少量的开支, 在第一阶段加载的 Roman 字体的子集会被重复在第二阶段完整的 Roman 字体时再加载一次. 这就是为了最小化回流的代价。
  • 许可证限制: 需要裁剪。

结论: 可以使用以下加强过的 严格的 FOFT 的变种。

有数据 URI 的严格 FOFT

这个不同的 FOFT 实现方式可以通过第一阶段加载的内容来改变机制。我们可以简单的以直接嵌入数据 URI 到标记语言的形式, 嵌入在线字体, 而不是使用一般的 JavaScript API 来初始化一个下载, 加载字体。就如之前讨论的, 这样会阻塞初始化渲染, 但是由于我们仅嵌入一小部分的子 Roman 在线字体, 对于完全消除FOUT, 这点代价还是值得的。

优点

  • 所有 严格的 FOFT 现存的优点.
  • 消除了 FOIT 并且对 Roman 字体极大地减少 FOUT。对在第二阶段加载的额外字体会发生一个小的回流并且当其他权重和样式被加载时, 但这个影响很小。

缺点

  • 所有 严格的 FOFT 现存的缺点。
  • 这个小的内联数据 URI 将少量的阻塞初始渲染. 我们用它交换 FOUT 大大的减少。
  • 亲自服务托管: 必须。

结论: 就我来看, 这就是目前的黄金标准。

有预加载 preload 的 严格 FOFT

这个不同的 FOFT 实现方式可以通过第一阶段加载的内容来改变机制。我们使用新的 preload 在线标准, 而不是使用一般的JavaScript API 来初始化一个下载, 加载字体。在之前已经介绍过 preload方法, 这会比之前更快的触发下载。

优点

  • 所有 严格的 FOFT 现存的优点。
  • 渲染性能: 下载应该比之前的方法早被触发。 我猜测这个甚至比 HTTP 的报头更戏剧性, 但还并没有证实我的预感. 这个方法比 有数据 URI 的严格 FOFT 更好, 他能使用浏览器的缓存重复(发送)请求, 而不是重复发送一样的在线字体, 与每一个服务器标记(语言)请求。

缺点

  • 所有 严格的 FOFT 现存的缺点。
  • 只使用一个在线字体样式。
  • 如上述所陈述的, 浏览器的支持有限 在我写这篇文章时, 只有 Blink 支持。
  • preload 会少量的增加初始化渲染的延迟(注意对比的数据由严格 CSS 的网站生成)。
  • 亲自托管: 可能需要。

结论: 当浏览器能更好的支持的时候,这会是新的黄金标准。






原文发布时间为:2016年07月28日

本文来自云栖社区合作伙伴掘金,了解相关信息可以关注掘金网站。

字体加载策略全面指南相关推荐

  1. html字体加载规则,CSS-等待字体加载,然后渲染网页

    CSS-等待字体加载,然后渲染网页 我正在使用@ font-face将字体嵌入到我的网站中. 首先,文本将作为系统默认值呈现,然后(假定字体文件已加载)正确的字体将在几分之一秒后呈现. 有没有一种方法 ...

  2. 【sping揭秘】6、IOC容器之统一资源加载策略

    Spring中的resource 我们先看看类之间的关系 注意我们的application是间接继承了resourceloader的,也就是说我们的application其实就是一个resourcel ...

  3. 【Cocos2d-X(2.x) 游戏开发系列之三】最新版本cocos2d-2.0-x-2.0.2使用资源加载策略

    前段时间cocos2dx更新了最新版本cocos2d­2.0­x­2.0.2,也从这个版本开始对于资源加载与管理都改变了策略. 在之前的加载方式都是通过沿用与cocos2d-iphone一样的加载资源 ...

  4. Web 性能优化:使用 CSS font-display 控制字体加载和替换

    作者 | 张旭乾       责编 | 欧阳姝黎 出品 | 峰华前端工程师 在编写网站的时候,或多或少都会用到一些网络上的字体,CSS 3 中虽然加入了对 Web Fonts(网络字体)的支持,但是浏 ...

  5. 浅析Android字体加载原理

    浅析Android字体加载原理 前言 之前在处理系统字体问题的时候,可借鉴的资料很少,遇到了很多坑,不得不了解Android字体加载原理,现抽空写一篇总结,来加深自己对这块的理解. 内容 概述 And ...

  6. 将WordPress后台的open-sans字体加载源从Google Fonts换为360 CDN

    2019独角兽企业重金招聘Python工程师标准>>> 针对最近因为Google fonts被墙导致WordPress 打开慢的问题,Jeff 在上一篇<Google Font ...

  7. Android系统字体加载流程

    一.背景 视觉同学提了一个需求,要求手机中显示的字体可以支持medium字体,经过分析,android原生的字体库中并没有中文的medium字体,如果使用bold,显示又太粗,为满足需求,需要分析an ...

  8. Android Webview使用自定义字体加载网页

    前言 有时,当我们使用Webview加载一个网页的时候,需要使用特定的字体来显示,这时就需要我们对页面做下处理! 方法 ①首先需要我们获得目标网页的HTML源码: URL url = new URL( ...

  9. Python Selenium.WebDriver 最强详解页面加载策略

    Python Selenium.WebDriver 网页加载策略『详细』 文章目录 Python Selenium.WebDriver 网页加载策略『详细』 一.网页加载策略

最新文章

  1. 一些JSON相关的函数
  2. 在查找预编译头时遇到意外的文件结尾。是否忘记了向源中添加“#include “pch.h“”?
  3. eeglab中文教程系列(6)-数据叠加平均{1}(Data averaging)
  4. web渗透测试 靶机系统 漏洞测试环境
  5. c++人脸特征保存到本地_尚邦小规模人脸识别布控系统
  6. create react app 在start后不清空terminal
  7. 11月18日站立会议
  8. 吴恩达DeepLearningCourse5-序列模型
  9. [html] html标签的属性值是否可以省略引号?为什么?
  10. python1到n的所有排列_非递归输出1-N的全排列的方法详解
  11. java qq在线客服,Java获得腾讯QQ在线状态(.net webservice) | 学步园
  12. MT6763,MT6763T(P23),MT6750T,MT6755(P10)参数比较
  13. 分销商城平台开发现成源码
  14. 计算机文本自定义,自定义文本编辑器
  15. GBIC模块、SFP模块、SFF模块介绍
  16. 金仕达程序化交易平台初步设计
  17. android图片分辨率改变,Android实现改变一个图片的像素值
  18. 如何有效的招聘技术人员
  19. 浅谈verilog hdl中parameter的用法
  20. ESP8266通过TCP透传连接OneNet云平台实现数据互传——保姆级教程

热门文章

  1. 2019的一些记录,共勉
  2. 试图5天学会python——Mooc 实例
  3. 电影旅行敲代码的To Do List
  4. STL (Seasonal-Trend decomposition procedure based on Loess) 时间序列分解
  5. 长沙夜经济,每天双十一
  6. 微信小程序原生开发——商品分类左右联动页面(类似于喜茶)
  7. 猫猫龙猫猫011:设置用户最大可打开文件数,进程数
  8. QGIS火星坐标转换插件
  9. 朋友圈很火的小电视网站源码
  10. Linux系统编程【文件IO、进程、进程间通信、信号、线程、互斥】