CSS 自定义字体实践

为了更好的视觉体验,设计稿中偶尔会对部分文字、数字会使用了非默认字体,例如 DIN CondensedDIN 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

可以看到其中的 655646883904,即字体子集文件大小只有几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;
}
  1. 对于一些系统中默认存在的字体,可以通过 local() 函数的方式进行使用。
  2. 由于 src 的处理顺序从上到下,所以一般 local() 放在第一项,woff2woffttf 按照顺序列出。

当浏览器解析到可用的字体时,便不会再继续向下寻找,所以这种顺序应该是对网络加载最友好的。

比如对于 Android 设备来说,可能没有 DIN Alternate 字体,则 local() 会失败,接下来该设备支持 woff2 的情况下,那么就只会尝试下载 woff2 文件。

unicode-range 也在一定程度上优化了网络加载,因为只有使用该字体的 element 内容符合 unicode-range 的情况下,浏览器才会从 src 中加载字体文件。

比如 <div style="font-family: 'DIN Alternate'">abc</div> 即便指明使用该字体,但由于其中的内容 abc 不在 unicode-range 的范围内,所以浏览器不会尝试获取字体文件。


到此为止,算是简单地完成了加载自定义字体所需要的全部工作,目前所做的这些可能只算最佳实践的一部分,但应对前端工作中偶尔出现的自定义字体也算够用。

相关推荐
_丿丨丨_4 小时前
XSS(跨站脚本攻击)
前端·网络·xss
天天进步20155 小时前
前端安全指南:防御XSS与CSRF攻击
前端·安全·xss
拾光拾趣录7 小时前
括号生成算法
前端·算法
拾光拾趣录8 小时前
requestIdleCallback:让你的网页如丝般顺滑
前端·性能优化
前端 贾公子8 小时前
vue-cli 模式下安装 uni-ui
前端·javascript·windows
拾光拾趣录8 小时前
链表合并:双指针与递归
前端·javascript·算法
@大迁世界8 小时前
前端:优秀架构的坟墓
前端·架构
期待のcode8 小时前
图片上传实现
java·前端·javascript·数据库·servlet·交互
hbrown9 小时前
Flask+LayUI开发手记(十一):选项集合的数据库扩展类
前端·数据库·python·layui
猫头虎9 小时前
什么是 npm、Yarn、pnpm? 有什么区别? 分别适应什么场景?
前端·python·scrapy·arcgis·npm·beautifulsoup·pip