浅色圆锥曲线爱好者PostsNotesAbout

如何减少字体文件尺寸

本 blog 最初选定英文字体的时候选择了Great Vibes这个字体,相对之下中日文的粗体字就会显得很不搭,一直在考虑解决。如果只是指定serif的话在 mac 端上能够显示想要的效果但是其他客户端都不行。自然应该是系统自带字体库的问题,最简单方法就是再加载一个外部字体。中日文都支持的字体里最有名的应该是noto-serif-sc,但是因为字符数很多,文件将近 7.7Mb。就算初次加载之后有 cache,初次加载的 cost 也太大了。

一顿搜索之后找到了fonttools这个开源项目,其中提供的pyftsubset这个工具可以对字体文件进行裁剪取出需要的字符。可惜并没有找到 node 对应的项目。

sh
$ pyftsubset --help
... --unicodes=<XXXX>[,<XXXX>...] Specify comma/whitespace-separated list of Unicode codepoints or ranges as hex numbers, optionally prefixed with 'U+', 'u', etc. For example, --unicodes=41-5a,61-7a adds ASCII letters, so does the more verbose --unicodes=U+0041-005A,U+0061-007A. The special strings '*' will choose all Unicode characters mapped by the font. ...

接下来使用gatsby的 query 获取所有的标题进行处理,在gatsby-node.js中加入prebuild的 hook:

query 如下:

graphql
{
allMdx {
edges {
node {
frontmatter {
title
}
}
}
}
}

整理 unicode 字符串并外部执行 py 命令:

js
const unicodes = [...new Set(titles.join("").replace(/[a-zA-Z0-9\s]/g, ""))]
.map(
char =>
"U+" +
char
.charCodeAt(0)
.toString(16)
.padStart(4, "0")
)
.join(",")

合并两者:

js
exports.onPreBuild = ({ graphql }) => {
console.log('preBuild fonts!')
return graphql(`
{
allMdx {
edges {
node {
frontmatter {
title
}
}
}
}
}
`).then(result => {
return new Promise(ok => {
const titles = result.data.allMdx.edges.map(
({ node }) => node.frontmatter.title
)
const unicodes = [...new Set(titles.join("").replace(/[a-zA-Z0-9\s]/g, ""))]
.map(
char =>
"U+" +
char
.charCodeAt(0)
.toString(16)
.padStart(4, "0")
)
.join(",")
exec(
`pyftsubset static/fonts/NotoSerifSC-Regular.woff2 --unicodes="${unicodes}" --flavor="woff2" `,
(err) => {
if (err) {
throw err
};
ok();
)
}
)
})
}

现在再确认一眼生成的NotoSerifSC-Regular.subset.woff2只有 72kB,差距还是非常巨大的。

© 2023