字库分割

您所在的位置:网站首页 nobility字体优化 字库分割

字库分割

2024-07-13 08:29| 来源: 网络整理| 查看: 265

对于中文字库来说,动辄几十 M 的体积非常常见。所以字体加载的优化就显得尤为重要。在研究了市面上现存的字体加载方案后,我总结出了一套性价比较高的字体加载方案以及所需的转换工具。

在介绍之前,咱们先来看一下现存方案的优缺点。

常见的字体加载方案 font-spider

最常见的应该要数 font-spider,网上关于它的介绍一抓一大把。font-spider 会解析你指定的 html 并统计其中的文字,最后对字库进行类似 “tree shaking” 的操作,只保留项目中出现的文字。

效果很好,最终的字库可能只有几百 b,但是缺点也很明显,由于项目历史久远,并且维护者在 README 中也说明了 不支持 javascript 动态插入的元素与样式,所以基本无法适应目前流行的前端三框架。

并且由于只能解析 html 中的文字,对于需要从后台读取显示大量数据的管理系统项目来说效果也不好。

加载完成前使用降级字体

浏览器对于首要字体不存在时的解决方案有两种:

加载完成前隐藏(FOIT, Flash Of Invisible Text) 加载完成前使用降级字体(FOUT, Flash Of Unstyled Text)。

而我们可以使用一个库:ontfaceobserver 来让所有浏览器都先使用降级字体,直到首要字体加载完成。

这个方案的优点是响应速度快,因为页面显示和字体加载是异步的。是这同时也是缺点,用户同样需要下载一个很大的字库文件,并且在下载完成时会有字体切换的效果。用户可能不太喜欢用着用着字体突然变了的感觉。

网络字体

在 @font-face 定义字体时,给 src 字段传递一个 url(xxx) 来加载网络上的字体。比较常见的字体托管平台有 Google Fonts 和 有字库。这些平台一般都会提供自己的字体加载优化方案。

优点是更好的字体加载速度,只要使用了平台内置的字体加载方案,基本都可以让字体加载速度成倍的提高。但是缺点也很明显,额外的平台带来了额外的维护成本。并且由于会访问别人的网站,就需要配置对应的 内容安全策略 ( CSP ),不然会被拦截导致字体加载不出来。

除此之外,外链的稳定性也是一个问题,更别提 google 那飘忽不定的访问速度。如果你是内网项目,那更可以直接 pass 掉这个方案。

字库分割 - 简单粗暴的本地字体托管方案

下面就来介绍一下我目前使用的字体加载方案。其实这个方案的核心还是 google fonts,打开谷歌字体提供的 noto sans sc 字体链接,可以看到,这其实就是一个 css 文件,而关键在于:google fonts 使用 unicode-range 将一个大型字体文件分割成了上百个小号文件,可以在 mdn 关于 unicode-range - CSS: Cascading Style Sheets | MDN (mozilla.org) 的介绍中看到:

The unicode-range CSS descriptor sets the specific range of characters to be used from a font defined by @font-face and made available for use on the current page. If the page doesn't use any character in this range, the font is not downloaded; if it uses at least one, the whole font is downloaded.

浏览器只会在页面使用了该范围中的字符时才会加载对应的字体“分片”。也就是说页面初始化时给浏览器一个目录,在页面要渲染字体时再去根据目录加载所需的字体文件。

这其实就相当于字体的“运行时按需加载”,不仅用起来省心,把 css 引入只来之后就不需要管了,对字体的加载速度也有了显著的提升。

这听起来是个不错的方案,现在唯一的问题就是,我们如何把这几百个文件挪到前端项目里来?不用担心,我已经做好了一个小工具:google-font-splitter - 一个用于下载谷歌分割字体的命令行工具,现已发布至 npm。

用法很简单:只需要提供一个谷歌字体的在线链接,它就会帮你把所有需要的字体文件下载到本地并做好路径转换工作。

下面简单介绍一下使用方法,可以分为三步:获取字体链接、下载字体、引入到前端项目。

第一步:获取字体链接

由于我们只是把谷歌字体中已经分割好的字体下载到本地,所以首要任务就是去谷歌字体里找到我们需要的字体,这里以 noto sans sc 为例:

找到对应的字体,在详情页下面选中需要的字体样式,然后在右侧的 Selected family 面板下方找到找到在线字体链接并将其复制出来:

注意,这里我们需要的是字体文件对应的 css 链接,不需要 复制整行 标签。

第二步:将在线字体下载为本地字体

现在我们来下载刚才复制的字体,首先找个空文件夹安装上文提到的工具:

npm install -g google-font-splitter

然后执行命令:

google-font-splitter "https://你复制出的在线字体链接"

比如我这里执行的命令就是 google-font-splitter "https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@100;300;400;500;700;900&display=swap",然后等一会,字体就下载好了:

gif 里可以看到,不仅所有的字体文件都下载好了,并且入口 css 文件(noto-sans-sc.css)中对应的引入路径也换成了对应的同级相对路径。这样直接把文件夹复制到项目里就可以使用。

脚本很简单,核心实现也不到一百行,有兴趣的同学可以研究一下。

第三步:引入到前端项目

接下来就很简单了,把下载好的文件夹复制到你想要的前端项目里,然后使用 引入就可以了。

你可以在 google-font-splitter - 在项目中引用 里边找到 vue、react 之类的框架引入方式。方式都大同小异,下面是就以 vue2 项目的一个引入为例了:

可以看到,41.7M 的 noto sans sc 字体加载下来只需要几百 k。虽然相对于前端文件来说还是很大,但起码达到了可用水平。

由于我们是相对引入,所以复制的时候带不带文件夹都行,只需要保证入口 css 和字体源文件目录同级即可。

工具还提供了几个配置项,如修改字体源文件的引入路径,修改入口文件名等,具体可以看 这里,本文不再赘述。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3