Blog/source/_posts/2021/03/中文网页字体动态裁剪.md
2022-03-16 22:24:24 +08:00

3.8 KiB

author title date tags category toc
SouthFox 中文网页字体动态裁剪 2021-03-12 21:28:56
技术
字体
技术 true

首先,我先在放个【矣】在这里。

比起字母系统语言,汉语在计算机世界上有着天然的弱势,锟斤拷锘锘锘这些编码问题本身就令人头大了,尤其对于互联网这个寸土寸金之地,想要在网页内展现自定义字体,首先就要先加载个几兆大小的字体文件,要这么做那就是极度的浪费和折磨了。

所以字体裁剪是必要的,有两种方向:

  • 提前准备常用字集进行裁剪

  • 提前计算出需要展示的字集再进行裁剪

第一种方式就是突出一个极致的懒,只需要做一次,就能不用再管了。缺点就是总会有不在常用字体里的“常用字”,这样网页加载出来的效果就会形成“犬牙交错”之感,看起来非常辣眼(要是选用的字体和默认字体差别非常大的话)。而且常用字内其实也不是每个字都用上了,所以还是会有浪费。

第二种方式就更优雅一点了,能保证字体里的每个字都是用上的。缺点就是麻烦了点儿,不过只要写个自动化脚本,这点麻烦也不算麻烦了。

压缩方案

当选 fonttools ,至少这项目现在还活跃着,其他类似的字体项目都停滞了蛮久时间的了……好像。

要使用直接通过 pip install 安装 fonttools就行了,要是还想压成 woff2 这种压缩率更高的格式还得再安装个 brotli

使用命令:

pyftsubset <字体>.ttf --text-file=<字符集文件>

当然,也可用 --text= 的选项来直接后面跟所需字符。

要压成 woff2 格式可以用 fonttools ttLib.woff2 compress <压缩后字体>.woff2 <被压字体>.ttf 的方式。

脚本代码

反正一个简单粗暴的循环怼上去就得了,去重可以用集合来去。

import os

path = os.getcwd()

filelist = []
for root, dirs, files in os.walk(path + '/source'):
    for name in files :
        filelist.append(os.path.join(root, name))

strset = set([])
for filename in  filelist:
    if '.md' not in filename:
        continue

    with open(filename, "r",encoding='utf-8') as f:
        for subset in f.read():
            strset.add(subset)

str_ = ''
a = 0
with open('strdb.txt', "w") as f:
    for i in list(strset):
        str_ += i
        a += 1
    print('%d Characters in all files.'%a)
    print(str_)
    f.write(str_)

source 下的 md 文件的字符提出来,再写入到 strdb.txt 以带后续使用。当然直接用 --text= 选项直接塞进命令里也可以,反正我是喜欢先写进文件的。

最后生成的字体文件在 80kb 左右,对于网页来说,已经是可以接受的程度了,当然这跟我选择的字体有关,是一款像素字体,不怎么占空间,如果是常规字体的话,大概会在上两三百左右吧。

  1. 首先是 Travis 部署上得用 python3 环境,要特别声明一下,二环境下会输出个零蛋,应该是版本之间语法的锅?
  2. 代码里没有解析配置文件里的中文语句,所以标语口号这种,可能就会没被解析到,不过我懒地再一个一个引入配置文件,所以还不如……我先在放个【矣】在这里。
  3. 确保文本在网页字体加载期间保持可见状态,即设置 font-display: swap 选项 在@font-face 内,要不然的话字体没加载出来文本会消失掉。

参考

  1. Fonttools
  2. 中文字体压缩的那些事——涂雨期的博客
  3. Font display