-
打个分吧:

前端字体性能优化

字体文件过大、FIOT(flash of invisible text)字体闪现问题

1分钟阅读
-
-

问题1:字体文件过大,解决方案:Fontmin - 字体子集化

介绍

Fontmin是一个纯JS字体子集化方案,用于压缩字体文件。

依赖node环境。

其原理是扫描项目中的文字,将用到的字从字体文件中单独拿出来组成一个子集字体文件。

可以达到大幅度减小字体文件尺寸的效果。

相关资源

安装

npm install --save-dev fontmin

使用

const fs = require("fs");
const Fontmin = require("fontmin");

//扫描文件目录
const scanFolder = (dir, done) => {
  let results = [];
  fs.readdir(dir, (err, list) => {
    if (err) {
      return done(err);
    }
    let i = 0;
    (function iter() {
      let file = list[i++];
      if (!file) {
        return done(null, results);
      }
      file = dir + "/" + file;
      fs.stat(file, (err, stat) => {
        if (stat && stat.isDirectory()) {
          scanFolder(file, (err, res) => {
            results = results.concat(res);
            iter();
          });
        } else {
          results.push(file);
          iter();
        }
      });
    })();
  });
};

//Fontmin根据文字内容生成压缩后的字体子集
const generateFinalHTML = (finalString) => {
  const fontmin = new Fontmin()
    .src('static/fonts/*.ttf')  // 需要压缩的所有字体文件
    .dest('static/fonts/')  // 压缩后文件存储路径
    .use(
      Fontmin.glyph({
        text: finalString,
        hinting: false,
      })
    )
    .use(
      Fontmin.ttf2woff({
        deflate: true,
      })
    );

  fontmin.run((err) => {
    if (err) {
      throw err;
    }
  });
};

//获取目录下所有文件的文字内容
scanFolder("dist", (n, results) => {
  let set = new Set();
  results.forEach((file) => {
    const result = fs.readFileSync(file, "utf8");
    const currentSet = new Set(result);
    set = new Set([...set, ...currentSet]);
  });
  generateFinalHTML(Array.from(set).join(""));
});

问题2:FOIT(Flash of Invisible Text )字体闪现问题

问题描述

浏览器在加载字体时,默认不展示文本内容,在现代浏览器中,FOIT会导致这种现象出现至多3秒。

如果有文字混搭(有的字体需要加载,有的字体不需要)那么用户可能就会发现“网页只显示部分字体”的情况,用户体验很差。

解决步骤1:font-display:swap :未加载到字体时,优先显示替代字体,而不是空白(MDN文档)。

font-display属性决定了一个@font-face在不同的下载时间和可用时间下是如何展示的。

@ font-face {
  font-family: ExampleFont;
  src: url(/path/to/fonts/examplefont.woff)format('woff'),
       url(/path/to/fonts/examplefont.eot)format('eot');
  font-weight: 400;
  font-style: normal;
  font-display: fallback;
}

解决步骤2:preload:预加载字体文件,提前加载字体。

<link rel="preload" type="font/woff" href="/fonturl" as="font" crossorigin="true">

解决步骤3:document.fonts.ready 接口:浏览器处理完成字体加载后的回调(加载成功或者失败都会触发回调)

document.fonts.ready.then(() => {
  // 字体加载完成后的逻辑
  this.fontLoaded = true;
});
上次更新:

评论区