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

731 阅读6分钟

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

前言

承接上文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 链接。

更多详情内容,请前往[原文-CSS3 使用@font-face 引入字体的兼容性方案及优化](原文-CSS3 使用@font-face 引入字体的兼容性方案及优化)

相关文献