为了更好的视觉体验,设计稿中偶尔会对部分文字、数字会使用了非默认字体,例如 DIN Condensed
、DIN Alternate
等字体。
DIN Alternate 字体图例 - 侵删请联系
创建字体子集
一般而言,字体文件尺寸不会很小,诚然目前浏览器、网络等外部因素比过去友好得多,尝试在一定程度优化字体文件的大小仍然有意义。
仍旧以 DIN Alternate
字体为例,DIN Alternate Bold.ttf
文件约有 152KB,这 152KB 中包含英文字母、数字、符号和其他的一些字符。而对我们而言,可能只会使用 0-9
这几个数字字符,其他字符纯属浪费网络资源,那么是否有办法只加载 0-9
这几个字符呢?
答案自然是肯定的,可以使用 glyphhanger - npmjs.com 这个包的能力来 "裁剪"原字体文件,取原字体文件中的几个字符生成新的字体子集文件。
glyphhanger
的安装大致如下,具体请参考 glyphhanger
文档:
具体请参考
glyphhanger
文档,毕竟写在这里的代码会过时。
bash
npm install -g glyphhanger # 全局安装
# 安装部分 python 包
# 目前 Mac 上估计都是 pip3 了
pip3 install fonttools
# 安装用于支持 woff2 字体格式
pip3 install brotli
glyphhanger
的使用也很简单,设置好需要的字体格式、所需要的字符以及字体文件即可。
bash
glyphhanger
--formats=woff2,woff,ttf # 要生成的格式
--whitelist=U+30-39,U+2E # 没有办法直接写数字0-9,需要使用U+的表示方式,多个区间使用逗号分隔,U+30-39表示0-9,U+2E表示英文句号
--subset=./DIN\ Alternate\ Bold.ttf # 需要处理的字体
通过 ls -al
看所生成的字体子集文件:
plaintext
a@b c % ls -al
total 216
drwxr-xr-x 6 a d 192 1 28 09:41 .
drwx------@ 1 a d 10496 1 28 09:41 ..
-rw-r--r-- 1 a d 6556 1 28 09:41 DIN Alternate Bold-subset.ttf
-rw-r--r-- 1 a d 4688 1 28 09:41 DIN Alternate Bold-subset.woff
-rw-r--r-- 1 a d 3904 1 28 09:41 DIN Alternate Bold-subset.woff2
-rw-r--r-- 1 a d 152012 1 28 09:41 DIN Alternate Bold.ttf
可以看到其中的 6556
、4688
和 3904
,即字体子集文件大小只有几KB。
使用字体子集
在 CSS 中使用字体子集时,也有需要注意的地方:
css
@font-face {
font-family: "DIN Alternate";
src:
// Mac 和 iOS 中有本地字体
local("DIN Alternate Bold"),
url('./assets/fonts/DIN_Alternate_Bold_subset.woff2') format('woff2'),
url('./assets/fonts/DIN_Alternate_Bold_subset.woff') format('woff'),
url('./assets/fonts/DIN_Alternate_Bold_subset.ttf') format('truetype');
// 范围 U+30-39 => 0-9 U+2E => .
unicode-range: U+30-39,U+2E;
// 对于 DIN Alternate 来说,只有 Bold 这么一个字体,设不设置 font-weight 看起来没有影响
font-weight: 700;
}
- 对于一些系统中默认存在的字体,可以通过
local()
函数的方式进行使用。 - 由于
src
的处理顺序从上到下,所以一般local()
放在第一项,woff2
、woff
、ttf
按照顺序列出。
当浏览器解析到可用的字体时,便不会再继续向下寻找,所以这种顺序应该是对网络加载最友好的。
比如对于 Android 设备来说,可能没有 DIN Alternate
字体,则 local()
会失败,接下来该设备支持 woff2
的情况下,那么就只会尝试下载 woff2
文件。
unicode-range
也在一定程度上优化了网络加载,因为只有使用该字体的 element 内容符合 unicode-range
的情况下,浏览器才会从 src
中加载字体文件。
比如 <div style="font-family: 'DIN Alternate'">abc</div>
即便指明使用该字体,但由于其中的内容 abc
不在 unicode-range
的范围内,所以浏览器不会尝试获取字体文件。
到此为止,算是简单地完成了加载自定义字体所需要的全部工作,目前所做的这些可能只算最佳实践的一部分,但应对前端工作中偶尔出现的自定义字体也算够用。