JyLie

V1

2022/02/27阅读:63主题:默认主题

CSS3 使用@font-face引入字体的兼容性方案及优化

引入第三方字体一定要注意字体版权问题

前言

承接上文web 端字体兼容性适配之后,好久没有总结 CSS3 引入字体 @font-face 相关的文章了。一是在掌握 @font-face 的基本使用要领后没遇过兼容性问题,二是觉得 @font-face 已经兼容 ie9+及现代浏览器了,兼容性问题基本可以忽略不计了。事与愿违的是,在多次实战中发现引入第三方字体会出现许多奇形怪状的问题,譬如字体文件的编码问题引发字体可以在桌面系统正常使用而在 Web 端不起作用、字体文件中英文或其他外语的字体行高差异问题、字体文件的等宽比在不同浏览器显示差异问题......现对web 端字体兼容性适配作补充,如果不妥请各位大佬抬手指正(#^.^#)。

字体兼容性

字体编码兼容

前段时间有几个需要引入第三方字体的项目,引入过西文、韩文、泰文、以及种类繁多让你眼花缭乱的中文字体,可能是因为引入那种中文字体比较多的缘故吧,老觉得中文字体的兼容性可能会多些,其中编码兼容性像一座大山。

或许你会遇到过这样的情景,字体在 Photoshop 可以正常使用,放在 Web 端通过 @font-face 引入后字体显示不起作用。与相似的还有引入字体在 IE、Firefox 等浏览器正常使用,在 chrome 浏览器却显示编码报错不起作用如:OTS parsing error: cmap: Failed to serialize table的情况,或者完全因为字体编码格式不是被该浏览器所支持。

“工欲善其事必先利其器”,解决编码问题最直接的办法当然是将字体转码处理了。这里推荐两个字体转码工具:

只需将字体转化为需要的字体格式即可,另外推荐使用.ttf格式,用途下面有细讲。

字体优化

字体压缩

字体文件体积一般少则 2~4M,多则能达到 20~30M 之多,因此 直接 引入第三方字体尚且存在很大缺陷,尤其是在移动端使用。

当然开发者的智慧是无穷的,社区对此类问题也提供了字体压缩的解决方案。

常用字体压缩有:

  • font-spider
  • fontmin

上述字体压缩工具的核心是,通过抽离指定预设的字符串来生成新的字体文件,因为排除了大量不需要的字符串集,抽离后的字体文件体积大大变小,从而达到字体压缩的效果。

font-spider

使用font-spider已经有几年时间了,用着方便也是比较推荐使用的。

详细的使用方法可以查看font-spider 官网

font-spider的主要用途是 将 .ttf 格式的字体文件根据需求预设 css 字体格式来生成字体文件。

特别注意的是,font-spider 只能将 .ttf 格式的字体文件转化为其他格式的字体文件。

fontmin

最近身边有同学也在使用 fontmin 来转化字体格式,因此也贴出来供大家参考食用。

详细的使用方法可以查看fontmin 官网

fontminfont-spider 的最大差异是,前者不需要指定**.ttf** 格式的字体文件进行转化,而是通过其配套的字体转化插件来定制使用。

使用 rel="preload" 优化字体加载

由于自定义字体只有当前页面被引用到的时候,浏览器才会对字体进行加载。为了更快的加载字体文件,可以使用rel="preload"来达到效果

<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin />

FOUT(Flash of Unstyled Text) 优化

FOIT(Flash of Invisible Text)问题:浏览器在加载字体的时候的默认表现形式,也就是在字体加载过程中,页面是看不到文本内容的。在现代浏览器中,FOIT 会导致这种现象出现至多 3 秒。FOIT 会导致很差的用户体验,这是我们需要尽量去避免的。

FOUT:在字体加载过程中使用默认的系统字体,字体加载完后显示加载的字体,如果超过了 FOIT(3s)字体还没加载,则继续使用默认的系统字体。

FOUT 特性:

  • 通过 @font-face 设置 属性 font-display 来实现,默认为 auto。
  • IE 浏览器和 Edge 不会等待 FOIT 超时才显示默认字体,会立即显示默认字体。FOUT 比 FOIT 好,但是需要注意它引起的 reflow。

为了实现 FOUT,一般可设置 font-displayswapfallbackoptional

  • swap:为字体提供一个非常小的阻塞周期和无限的交换周期。(自定义字体加载成功即显示字体样式,可以在页面中看到的一个字体替换的效果)
  • fallback:为字体提供一个非常小的阻塞周期和短暂的交换周期。(Gives the font face an extremely small block period (100ms or less is recommended in most cases) and a short swap period (3s is recommended in most cases).)
  • optional:为字体提供一个非常小的阻塞周期,并且没有交换周期。(Gives the font face an extremely small block period (100ms or less is recommended in most cases) and a 0s swap period)
@font-face {
  font-family'fcustom';
  font-display'swap';
  font-display'fallback';
  font-display'optional';
}

使用监听字体加载

FontFaceObserver

通过使用插件 npm i fontfaceobserver 来监听字体加载完成,从而按需设置字体样式。

在字体加载前预算一种字体或使用 loading 效果什么的,字体加载成功后切换字体即可

// css 中 @font-face 已定义好
import FontFaceObserver from 'fontfaceobserver';

function loadfont({
  var ffo = new FontFaceObserver('My Family');
  ffo.load().then(() => {
    document.getElementById('fcustom').style.fontFamily = 'My Family';
  });
}

Font Load API

方法效果同 FontFaceObserver。

使用 Font Load API 加载字体,字体在加载完成前预算一种字体,字体加载完成切换相应的 CSS 即可。

但是需注意 Font Load API 是原生的 API,有兼容性问题。

<script>
  document.fonts.load('1em open_sansregular').then(function({
    var docEl = document.documentElement;
    docEl.className += ' open-sans-loaded';
  });
</script>

<style>
  .open-sans-loaded h1 {
    font-family: open_sansregular;
  }
</style>

字体转 BASE64URI

核心要义就是将@font-face 中定义字体时的路径直接改为字体的 base64 编码。

  • 优点:因为不会产生 FOIT 和 FOUT。所以不会有 reflow 和 repaint。
  • 缺点:
    • 字体转成 base64 也会很大,会影响页面首次加载速度。
    • 不支持逗号分隔的形式加载多种格式的字体,只能加载一种格式字体。这导致你为了尽可能保证所有浏览器都可以兼容,通常会指定为 woff 格式,因为 woff 格式兼容性好,但是却没法使用更小体积的 woff2 格式,因为 woff2 格式兼容性差点。

异步加载 BASE64 格式 URI 字体

通过异步的方式插入带有 BASE64 格式 URI 字体的 CSS 链接。

至此笔者已经词穷了,下面是 CV 大佬们的博文来的,文末已贴出出处。

FOFT(Flash of Faux Text)

FOFT 会把字体的加载分成多个部分,首先加载罗马网络字体,然后会在加载真实的粗体和斜体的时候立即使用 font-synthesis 属性渲染粗体和斜体的变体。

这种方法是基于[使用 Font Load API + FOUT + class 切换]这种方式的,非常适合加载同一种字体但是不同粗细,字形的场景,比如罗马、粗体、斜体、粗斜体等。

我们将这些字体分成 2 阶段:

  • 第一阶段是罗马字体
  • 然后立即渲染人造粗体和斜体
  • 最后(第二阶段)用真实字体替代

这里面还可以使用 sessionStorage 优化访问重复视图的场景。

CRITICAL FOFT

CRITICAL FOFT 和标准的 FOFI 的唯一区别就在于第一阶段罗马字体的加载,CRITICAL FOFT 不会加载罗马字体的全集,只会加载它的一个子集(比如 A-Za-z0-9),全集会在第二阶段加载。

CRITICAL FOFT WITH DATA URI

和 CRITICAL FOFT 的唯一区别就是罗马子集字体的加载方式,前面是用 Font Load API 完成了,这里会将马子集字体硬编码成 BASE64 URI 的形式加载。

CRITICAL FOFT WITH PRELOAD

同上面的唯一区别还是第一阶段罗马子集字体的加载方式,它采用的是 preload 的形式加载。

相关文献

分类:

前端

标签:

CSS

作者介绍

JyLie
V1