--- author: SouthFox title: 中文网页字体动态裁剪 date: 2021-03-12 21:28:56 tags: - 技术 - 字体 category: 技术 toc: true --- 首先,我先在放个【矣】在这里。 比起字母系统语言,汉语在计算机世界上有着天然的弱势,**锟斤拷**和**锘锘锘**这些编码问题本身就令人头大了,尤其对于互联网这个寸土寸金之地,想要在网页内展现自定义字体,首先就要先加载个几兆大小的字体文件,要这么做那就是极度的浪费和折磨了。 所以字体裁剪是必要的,有两种方向: - 提前准备常用字集进行裁剪 - 提前计算出需要展示的字集再进行裁剪 第一种方式就是突出一个极致的懒,只需要做一次,就能不用再管了。缺点就是总会有不在常用字体里的“常用字”,这样网页加载出来的效果就会形成“犬牙交错”之感,看起来非常辣眼(要是选用的字体和默认字体差别非常大的话)。而且常用字内其实也不是每个字都用上了,所以还是会有浪费。 第二种方式就更优雅一点了,能保证字体里的每个字都是用上的。缺点就是麻烦了点儿,不过只要写个自动化脚本,这点麻烦也不算麻烦了。 ## 压缩方案 当选 [fonttools](https://github.com/fonttools/fonttools) ,至少这项目现在还活跃着,其他类似的字体项目都停滞了蛮久时间的了……好像。 要使用直接通过 ```pip install``` 安装 ```fonttools```就行了,要是还想压成 ```woff2``` 这种压缩率更高的格式还得再安装个 ```brotli``` 。 使用命令: ```pyftsubset <字体>.ttf --text-file=<字符集文件>``` 当然,也可用 ```--text=``` 的选项来直接后面跟所需字符。 要压成 ```woff2``` 格式可以用 ```fonttools ttLib.woff2 compress <压缩后字体>.woff2 <被压字体>.ttf``` 的方式。 ### 脚本代码 反正一个简单粗暴的循环怼上去就得了,去重可以用集合来去。 ```python 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](https://github.com/fonttools/fonttools) 2. [中文字体压缩的那些事——涂雨期的博客](https://hsingko.github.io/post/compress_webfont/) 3. [Font display](https://web.dev/font-display/)