使用 Fontconfig 治理 Linux 字体
前言
为什么会有这个指南
- 我浏览过许多介绍 fontconfig 配置的文章,但大多数配置难于理解和维护,要么是复制粘贴不求甚解。
- 官方文档实在是晦涩难懂。
配置路径
- 有一些说法,号称直接修改
/etc/fonts/
下的配置文件最为简单。可千万别这么做!如果改动过,请恢复原始文件。 - 正常来讲,应该把我们的配置文件加入家目录下的
~/.config/fontconfig/
。 - 如果文件过于冗长,可以采取
conf.d
进行拆分。
⚠️ 警告
随意修改系统配置文件不是一个好习惯,请牢记。
字体合成
fontconfig 的字体匹配机制为 Linux 程序提供了字体加载列表, 按先后顺序依次渲染字体。这意味着什么?这意味着不再需要那些合成字体了。
举个简单的例子,你想要使用 JetBrains Mono
字体作为等宽字体,使用 Nerd Fonts
字体提供 NF 图标,使用 Twemoji
字体提供 Emoji
,使用 MiSans
提供中文字体,使用 MiSans L3
提供生僻字,同时你的电脑上安装了许多的字体,正常情况下不会按照你想要的顺序加载。
现在给你 1 分钟时间,思考怎么办。
一个通用的办法就是用字体合并工具,按顺序合并这些字体,看起来没有问题对吧。
现在某一个字体更新了,你又需要合并一次,过几天另一个字体更新了,再来一次,是不是感觉哪里不太对。
让我们来看看 Arch Linux 上有多少打过补丁的 NF 字体:ArchLinux-Nerd-Font。
截至本文撰写时间(2025-03-29),67 种。是不是感觉不可思议。但这确实是现在的字体常态。所以我们需要 fontconfig 的字体合成功能。来看以下内容:
<match target="pattern">
<test name="family">
<string>sans-serif</string>
</test>
<edit binding="strong" mode="prepend" name="family">
<string>Noto Sans CJK SC</string>
<string>Iosevka Aile</string>
<string>Twemoji</string>
</edit>
</match>
这种 font fallback 的方式,即可让程序按照以下顺序渲染字体:
Noto Sans CJK SC -> Iosevka Aile -> Twemoji
在此我优先指定中英文使用 Noto Sans CJK SC 来渲染,西文使用 Iosevka Aile 渲染,emoij 使用了字体 Twemoji。
那么还有很多没指定的字形怎么办呢,比如日文,韩文,火星文?没关系,那些都是系统配置中解决的,只要安装了相应字体,fontconfig 自然能帮我找到它们。
同时,即使我系统里有多个中文字体,也能保证程序使用 Noto Sans CJK SC 渲染字体而不是别的中文字体。
好耶!
上两句话都是骗你的。😕
为什么下文会讲。
简单测试一下你的字体
使用以下 html 代码测试你的浏览器字体支持情况:
<h2><div style="font-family: sans-serif">异体字(无衬线)</div></h2>
<div style="font-family: sans">
<p>遍角次亮采之门 默认</p>
<p lang="zh-cn">遍角次亮采之门 中文(大陆) lang=zh-cn</p>
<p lang="zh-tw">遍角次亮采之门 中文(台湾) lang=zh-tw</p>
<p lang="zh-hk">遍角次亮采之门 中文(香港) lang=zh-hk</p>
<p lang="ja">遍角次亮采之门 日文 lang=ja</p>
<p lang="ko">遍角次亮采之门 韩文 lang=ko</p>
</div>
<h2><div style="font-family: serif">异体字(衬线)</div></h2>
<div style="font-family: serif">
<p>遍角次亮采之门 默认</p>
<p lang="zh-cn">遍角次亮采之门 中文(大陆) lang=zh-cn</p>
<p lang="zh-tw">遍角次亮采之门 中文(台湾) lang=zh-tw</p>
<p lang="zh-hk">遍角次亮采之门 中文(香港) lang=zh-hk</p>
<p lang="ja">遍角次亮采之门 日文 lang=ja</p>
<p lang="ko">遍角次亮采之门 韩文 lang=ko</p>
</div>
如果你的字体配置一切正确,那么结果应如图所示: