中文字库嵌入Web时的分割与裁剪
立泉可能注意到这个博客站点的字体有点奇怪,并不是常见的无衬线黑体
,而是一种接近宋体
但又像手写楷书
的字体。其实是一款兼顾排版和中文美感的霞鹜文楷开源字体,但要将它嵌入博客中,需要解决一些应用中文字库的典型问题。
分割
其中最大的问题是中文字库的庞大体积,英文字库无非是字母和符号,如JetBrains Mono的WOFF2
文件体积仅为92KB,可以非常方便的在Web
中无感加载。但中文字库收录的汉字数以千计,而且笔画复杂,以8000字的霞鹜文楷GB
为例,Regular
字重的TTF
文件为18.3MB,如果加上常用的Bold
字重,体积就已经超过36MB,这么大的单体资源对网页加载是不可接受的。
所以中文字库必须分割,按常用字顺序以百KB为单位分割为多个WOFF2
文件,再由页面按需加载。
/* CSS支持为字体文件指定其包含的字符编码范围 */
@font-face {
font-family: "LXGW WenKai GB";
src: url("https://hosturl.com/01.woff2") format("woff2");
font-style: normal;
font-weight: 400;
font-display: swap;
/* 字符编码范围 */
unicode-range: U+305e3, U+305f6, U+3067d ...;
}
@font-face {
font-family: "LXGW WenKai GB";
src: url("https://hosturl.com/02.woff2") format("woff2");
font-style: normal;
font-weight: 400;
font-display: swap;
/* 字符编码范围 */
unicode-range: U+2ce29-2ce2a, U+2ce31, U+2ce7c ...;
}
其实用过Google Fonts就会知道它对中文字库也是这么处理的,所以现在问题就变成如何分割字库。
搜寻发现中文网字计划的cn-font-split项目,一个简单命令就可以把TTF
文件分割为数百个60KB的WOFF2
文件并生成CSS
代码,也支持指定要裁剪的字符编码范围,只生成包含所需字符的字库文件。
# 执行分割,指定输入TTF文件和输出目录
cn-font-split -i=/Users/apqx/Downloads/Input.ttf -o=/Users/apqx/Downloads/Output
配合浏览器缓存策略,每个页面加载的字体资源至多也不过几百KB,已属正常范围。这个问题解决后,选择字体就再不用为此纠结,放心使用喜欢的中文字库。
裁剪
我的博文会经常嵌入代码块,之前一直使用等宽的JetBrains Mono
字体,但应用霞鹜文楷
后发现英文黑体
和中文楷体
混在一起总感觉怪怪的…所幸霞鹜文楷
也提供等宽版本,但却是包含完整8000汉字的TTF
字库,这些汉字与已有字库重叠,而我所需只是其中的英文和符号。
借助cn-font-split
的裁剪功能,可以从TTF
中提取出指定范围的字符,生成独立的WOFF2
文件。
import {fontSplit} from "cn-font-split";
await fontSplit({
// 要分割的字体文件
FontPath: `/Users/apqx/Downloads/Input.ttf`,
// 输出目录
destFold: `/Users/apqx/Downloads/Output`,
// 输出格式 woff2
targetType: "woff2",
// 分包大小 70KB
chunkSize: 70 * 1024,
// 关闭自动分包,只打包 subsets 中指定的字符
autoChunk: false,
// 指定要打包的字符
subsets: [
// 数字、字母、符号
'1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`~!@#$%^&*()-_=+\\|{}[];:\'"<>,.?/ '
.split("")
.filter(Boolean)
.map((i) => i.charCodeAt(0))
],
testHTML: true,
threads: {},
previewImage: {},
});
同理博客中还存在一些使用手写字体的中文片段,没必要为它们引入整个字库,也是裁剪处理。