JyLie

vuePress-theme-reco JyLie    2017 - 2023
JyLie

Choose mode

  • dark
  • auto
  • light
主页
分类
  • API
  • HTML
  • css
  • vue
  • Linux
  • Docker
  • Webpack
  • WebGL
  • PixiJS
  • Github
  • BOM
  • XML
  • bug
  • ie
  • uniapp
  • IE
  • mysql
  • font
  • bom
  • canvas
  • video
  • html
  • JavaScript
  • js
  • 运算符
  • RegExp
  • 编码
  • MiniApp
  • nginx
  • Tool
  • node.js
  • cat
  • nodejs
  • protocol
  • URL
  • FLOW
  • DNS
  • Protocol
  • python
  • 安全
  • linux
  • shell
  • IDE
  • Packer
  • ViteJS
  • git
  • vendor
  • WebApp
  • WebView
  • Window API
  • webview
  • 规范
标签
时光轴
GitHub
author-avatar

JyLie

74

Article

79

Tag

主页
分类
  • API
  • HTML
  • css
  • vue
  • Linux
  • Docker
  • Webpack
  • WebGL
  • PixiJS
  • Github
  • BOM
  • XML
  • bug
  • ie
  • uniapp
  • IE
  • mysql
  • font
  • bom
  • canvas
  • video
  • html
  • JavaScript
  • js
  • 运算符
  • RegExp
  • 编码
  • MiniApp
  • nginx
  • Tool
  • node.js
  • cat
  • nodejs
  • protocol
  • URL
  • FLOW
  • DNS
  • Protocol
  • python
  • 安全
  • linux
  • shell
  • IDE
  • Packer
  • ViteJS
  • git
  • vendor
  • WebApp
  • WebView
  • Window API
  • webview
  • 规范
标签
时光轴
GitHub
  • CSS3 使用@font-face引入字体的兼容性方案及优化

    • @font-face的语法规则
      • 字体编码兼容
        • 字体压缩
          • font-spider
          • fontmin
        • 使用 rel="preload" 优化字体加载
          • FOUT(Flash of Unstyled Text) 优化
            • 使用监听字体加载
              • FontFaceObserver
              • Font Load API
            • 字体转 BASE64URI
              • 异步加载 BASE64 格式 URI 字体
                • FOFT(Flash of Faux Text)
                  • CRITICAL FOFT
                    • CRITICAL FOFT WITH DATA URI
                      • CRITICAL FOFT WITH PRELOAD

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

                      vuePress-theme-reco JyLie    2017 - 2023

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


                      JyLie 2022-02-26 fontwebfontcss

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

                      # 前言

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

                      # css 引入外部字体

                      css 通过@font-face 的方式引入外部字体。

                      且不同浏览器对引入字体的格式有差别

                      浏览器的兼容性,如下所示:

                      Browser @font-face TrueType WOFF EOT SVG SVGZ
                      IE 4+ 9+ 9+ 4+
                      Firefox 3.5+ 3.5+ 3.6+
                      Chrome 4+ 4+ 6+ 4+ 6+
                      Safria 3.1+ 3.1+ 6+ 3.1+ 3.1+
                      Opera 10+ 10+ 11.1+ 10+ 10+

                      由上归纳可得:

                      • .TTF或.OTF,适用于IE 9+、Firefox 3.5+、Safari 3.1+、Opera 10+
                      • .EOT,适用于Internet Explorer 4.0+
                      • .SVG,适用于 Chrome、IPhone

                      最终得出结论:.eot + .ttf /.otf + svg + woff = 所有浏览器的完美支持

                      # @font-face的语法规则

                      @font-face的语法规则如下:

                      @font-face {
                        [font-family: <family-name>;]?
                        [src: [ <uri> [format(<string>#)]? | <font-face-name> ]#;]?
                        [unicode-range: <urange>#;]?
                        [font-variant: <font-variant>;]?
                        [font-feature-settings: normal|<feature-tag-value>#;]?
                        [font-stretch: <font-stretch>;]?
                        [font-weight: <weight>];
                        [font-style: <style>];
                      }
                      
                      1
                      2
                      3
                      4
                      5
                      6
                      7
                      8
                      9
                      10

                      对此,我们需要事先准备需要引入字体源件,然后通过 css 定义@font-face进行引入。

                      @font-face {
                        font-family: 'YourWebFontName';
                        src: url('YourWebFontName.eot'); /* IE9 Compat Modes */
                        src: url('YourWebFontName.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('YourWebFontName.woff') format('woff'),
                          /* Modern Browsers */ url('YourWebFontName.ttf') format('truetype'), /* Safari, Android, iOS */
                            url('YourWebFontName.svg#YourWebFontName') format('svg'); /* Legacy iOS */
                      }
                      
                      .ff-fcustom {
                        font-family: 'YourWebFontName';
                      }
                      
                      1
                      2
                      3
                      4
                      5
                      6
                      7
                      8
                      9
                      10
                      11

                      # 字体兼容性

                      # 字体编码兼容

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

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

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

                      • Webfont Generator
                      • cloudconvert Generator

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

                      # 字体优化

                      # 字体压缩

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

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

                      常用字体压缩有:

                      • font-spider
                      • fontmin

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

                      # font-spider

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

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

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

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

                      # fontmin

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

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

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

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

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

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

                      # 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-display 为 swap、fallback 或 optional。

                      • 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';
                      }
                      
                      1
                      2
                      3
                      4
                      5
                      6

                      # 使用监听字体加载

                      # 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';
                        });
                      }
                      
                      1
                      2
                      3
                      4
                      5
                      6
                      7
                      8
                      9

                      # 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>
                      
                      1
                      2
                      3
                      4
                      5
                      6
                      7
                      8
                      9
                      10
                      11
                      12

                      # 字体转 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 的形式加载。

                      # 相关文献

                      • 字体转码工具-Webfont Generator
                      • 字体转码工具- cloudconvert Generator
                      • font-spider 官网
                      • fontmin 官网
                      • fontfaceobserver 插件
                      • MDN - font-display
                      • CSS @font-face 性能优化
                      • Better @font-face with Font Load Events
                      • A COMPREHENSIVE GUIDE TO FONT LOADING STRATEGIES
                      • web 端字体兼容性适配
                      • 原文-CSS3 使用@font-face 引入字体的兼容性方案及优化