PageSourceSearch

https://catcat.cc/post/2021-03-07/

html catcat.cc collected 2026-09-25 19:57:37 UTC 69,795 bytes, 1,009 lines download raw bytes

1<!DOCTYPE html>
2<html lang="zh"><meta charset="utf-8"><meta name="generator" content="Hugo 0.121.1"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
3<meta name="color-scheme" content="light dark">
4<meta name="supported-color-schemes" content="light dark"><title>用 fontconfig 治理 Linux 中的字体&nbsp;&ndash;&nbsp;双猫CC</title>
5
6
7
8
9
10
11<style title="Normalize iconfont">.icon {
12  width: 1em;
13  height: 1em;
14  vertical-align: -0.15em;
15  fill: currentColor;
16  overflow: hidden;
17}</style>
18
19<link rel="stylesheet" href="/css/core.f57826f016b449d3810d95073bdf2f69ed3e8707339e01cf7056beb995e52fe0e7fc16a59be44c6e56ec30a5d875efd4.css" integrity="sha384-9Xgm8Ba0SdOBDZUHO98vae0&#43;hwczngHPcFa&#43;uZXlL&#43;Dn/Balm&#43;RMblbsMKXYde/U">
20
21<meta name="twitter:card" content="summary" />
22<meta name="twitter:title" content="用 fontconfig 治理 Linux 中的字体" />
23<meta name="description" content="在上一篇《Linux fontconfig 的字体匹配机制》当中,
24我们已经了解过了 fontconfig 的原理。没想到一晃过去了 4 个月之久,
25别忘了还缺少实践部分呢!
26现在就一起来实践一把 fontconfig 的配置吧。">
27
28
29<script src="/js/base.c6a9c6a78dedefedc8224acf08e96c30ba22f87a833569bfdb3180492a837253d90f17b769814b153c49a9807e927d61.js" defer integrity="sha384-xqnGp43t7&#43;3IIkrPCOlsMLoi&#43;HqDNWm/2zGASSqDclPZDxe3aYFLFTxJqYB&#43;kn1h"></script>
vendor: 1 bytes, line 29
29
30<script>(() => {
31  // ns-params:@params
32  var host = "https://catcat.cc/srv/comments";
33  var locale = "zh";
34  var site_id = "catcat.cc";
35  var theme = "light";
36  var url_prefix = "https://catcat.cc";
37
38  // <stdin>
39  remark_config = {
40    host,
41    locale,
42    no_footer: true,
43    components: []
44    // 改成在相应页面手动打开
45  };
46  if (site_id) {
47    remark_config.site_id = site_id;
48  }
49  if (url_prefix) {
50    remark_config.url = url_prefix + window.location.pathname;
51  }
52  if (theme) {
53    remark_config.theme = theme;
54  }
55})();
56</script>
56
57
58
59
60
61<script>remark_config.components = ["embed"]</script>
61
62
63
64<script src="/js/post.c264c83900a4a22334336ad0ee0d1de6cc1486260c527931350e9eaaae042690404257558bf4739b4ede42a567a21b33.js"defer
65  integrity="sha384-wmTIOQCkoiM0M2rQ7g0d5swUhiYMUnkxNQ6eqq4EJpBAQldVi/Rzm07eQqVnohsz"></script>
65
66
67
68<script type="application/ld+json">
69  {
70    "@context": "https://schema.org/",
71    "@type": "BlogPosting",
72    "headline": "用 fontconfig 治理 Linux 中的字体",
73    "author": {
74      "@type": "Person",
75      "name": "rydesun"
76    },
77    "datePublished":"2021-03-07",
78    "dateModified":"2021-03-07"}
79</script>
79
80
81
82  <link rel="alternate" type="application/rss+xml" href="/index.xml" title="双猫CC">
83
84
85
86<script>!function(e,n){for(var o=0;o<e.length;o++){var r=n.createElement("script"),c=".js",d=n.head||n.body;"noModule"in r?(r.type="module",c=".mjs"):r.async=!0,r.defer=!0,r.src=remark_config.host+"/web/"+e[o]+c,d.appendChild(r)}}(remark_config.components||["embed"],document);
87</script>
87
88<body><section id="header">
89    <div class="header wrap"><span class="header left-side"><a class="site home" href="/"><span class="site name">双猫CC</span></a></span>
90        <span class="header right-side">
91<div class="nav wrap">
92  <nav class="nav"><a class="nav item link" href="/index.xml"title="">
93        <svg class="icon" aria-hidden="true">
94          <use xlink:href="#icon-rss-square"></use>
95        </svg>
96        <span>RSS</span>
97      </a><a class="nav item link" href="/about/"title="关于我">
98        <svg class="icon" aria-hidden="true">
99          <use xlink:href="#icon-box-heart"></use>
100        </svg>
101        <span>CatchCat</span>
102      </a><button id="theme-changer" class="nav item"
103      onclick="themeManager.setNextTheme()" title="切换主题">
104      <svg class="icon" aria-hidden="true">
105        <use xlink:href="#icon-lightbulb"></use>
106      </svg>
107    </button>
108  </nav>
109</div>
110</span></div></section><section id="content">
111
112
113<main id="article-and-sidebar">
114  <div class="article-container"><section class="article header">
115    <h1 class="article title">用 fontconfig 治理 Linux 中的字体</h1><p class="article date">2021年03月07日</p></section><article class="article markdown-body"><p>在上一篇<a href="/post/2020-10-31/">《Linux fontconfig 的字体匹配机制》</a>当中,
116我们已经了解过了 fontconfig 的原理。没想到一晃过去了 4 个月之久,
117别忘了还缺少实践部分呢!
118现在就一起来实践一把 fontconfig 的配置吧。</p>
119<h2 id="混乱的现状">混乱的现状</h2>
120<p>我浏览过一些介绍 fontconfig 配置的文章,
121要么是配置难于理解和维护,
122要么是复制粘贴不求甚解。所以我现在的目标是,找出一个最
123简单的方案,同时还要把各类问题处理好。</p>
124<h3 id="配置路径">配置路径</h3>
125<p>有一些说法,号称直接修改<code>/etc/fonts/</code>下的配置文件最为简单。
126可千万别这么做!<strong>如果改动过,请恢复原始文件。</strong>
127正常来讲,应该把我们的配置文件加入家目录下的<code>~/.config/fontconfig/</code>,
128不要添加在系统端。
129为了覆盖系统端的配置,
130可以在用户目录下的 fontconfig 配置中使用 <strong>强绑定</strong> 规则。
131关于强弱绑定规则对字体配置的影响效果,
132我在上一篇文章里的小节
133<a href="/post/2020-10-31/#字体得分和强弱绑定">字体得分和强弱绑定</a>
134当中介绍过。</p>
135<p>使用强绑定后,
136系统端的所有配置不会再干扰我们的配置。
137系统端的配置的作用是为了能够在我们自己的配置不够用的情况下,
138依旧能够提供一些有效的字体。或者说,它们的作用是仅作为
139最后的 fallback 机制来使用。
140当然,前提是我们一定要在用户配置中使用强绑定规则,切记。</p>
141<h3 id="关于合成字体">关于合成字体</h3>
142<p>fontconfig 的字体匹配机制为 Linux 程序提供了字体 fallback 列表,
143按先后顺序依次渲染字体。这意味着什么?不再需要那些合成字体了。
144在 Linux 上,你无需使用更纱黑体;为了用上 Nerd Fonts 图标字体,
145你也不需要给字体打上 Nerd fonts 补丁;当你想让中文字体整合
146另一个英文字体,不需要把它们合成一个字体。甚至你想让某个字体的
147某个字形由另一个字体来提供,
148这些需求统统都可以通过配置 fontconfig 来实现。</p>
149<p>一个最简单的思路,本文也基于该思路:
150不让程序使用某个具体的字体,而是使用通用字体族名 (Generic Font Family)。
151比如,让程序使用 sans-serif,也就是默认的无衬线字体。
152然后,使用 fontconfig 配置:</p>
153<div class="highlight"><div class="chroma">
154<table class="lntable"><tr><td class="lntd">
155<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
156</span><span class="lnt"> 2
157</span><span class="lnt"> 3
158</span><span class="lnt"> 4
159</span><span class="lnt"> 5
160</span><span class="lnt"> 6
161</span><span class="lnt"> 7
162</span><span class="lnt"> 8
163</span><span class="lnt"> 9
164</span><span class="lnt">10
165</span></code></pre></td>
166<td class="lntd">
167<pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="nt">&lt;match</span> <span class="na">target=</span><span class="s">&#34;pattern&#34;</span><span class="nt">&gt;</span>
168</span></span><span class="line"><span class="cl">  <span class="nt">&lt;test</span> <span class="na">name=</span><span class="s">&#34;family&#34;</span><span class="nt">&gt;</span>
169</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>sans-serif<span class="nt">&lt;/string&gt;</span>
170</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/test&gt;</span>
171</span></span><span class="line"><span class="cl">  <span class="nt">&lt;edit</span> <span class="na">name=</span><span class="s">&#34;family&#34;</span> <span class="na">mode=</span><span class="s">&#34;prepend&#34;</span> <span class="na">binding=</span><span class="s">&#34;strong&#34;</span><span class="nt">&gt;</span>
172</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Noto Sans CJK SC<span class="nt">&lt;/string&gt;</span>
173</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Noto Sans<span class="nt">&lt;/string&gt;</span>
174</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Twemoji<span class="nt">&lt;/string&gt;</span>
175</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/edit&gt;</span>
176</span></span><span class="line"><span class="cl"><span class="nt">&lt;/match&gt;</span>
177</span></span></code></pre></td></tr></table>
178</div>
179</div><p>这种 font stack 的方式,即可让程序按照以下顺序渲染字体:</p>
180<pre tabindex="0"><code>Noto Sans CJK SC —&gt; Noto Sans -&gt; Twemoji
181</code></pre><p>我在此优先指定中英文使用 Noto Sans CJK SC 来渲染,
182一些西文使用 Noto Sans 渲染,emoij 使用了字体 Twemoji。
183那么还有很多没指定的字形怎么办呢,比如腓尼基字母、皇家
184亚兰字母?没关系,那些都是在系统端的配置中解决的,我只要
185安装了相应字体,fontconfig 自然能帮我找到它们。
186同时,即使我系统里有多个中文字体,我也能保证程序使用
187Noto Sans CJK SC 渲染字体而不是别的中文字体。</p>
188<p>上一句话是骗人的。😕</p>
189<p>fontconfig 的解决方案不是完美的,合成字体依旧有它们的
190价值。这体现在一些对 fontconfig 支持不良的 Linux 程序上。
191对于 Windows 用户来讲,合成字体是一个很好的解决方案
192(因为他们没有 fontconfig)。
193尽管如此,我也强烈建议 Linux 用户配置好 fontconfig,而不是
194从一开始就使用合成字体。使用 fontconfig 实现字体
195的 fallback 机制,相比合成字体的优势是明显的:</p>
196<p><strong>自由组合,灵活搭配。</strong></p>
197<p>每次升级合成字体,你都需要重新打补丁生成该合成字体。
198如果是别人帮你提供好的合成字体那还好说,
199从网上下载、从软件仓库安装就完事了。
200比如说,为了能在西文字体中使用来自 Nerd fonts 的字形,
201看一看 archlinuxcn 社区仓库打包了多少份 Nerd Fonts:</p>
202<div class="highlight"><div class="chroma">
203<table class="lntable"><tr><td class="lntd">
204<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
205</span><span class="lnt"> 2
206</span><span class="lnt"> 3
207</span><span class="lnt"> 4
208</span><span class="lnt"> 5
209</span><span class="lnt"> 6
210</span><span class="lnt"> 7
211</span><span class="lnt"> 8
212</span><span class="lnt"> 9
213</span><span class="lnt">10
214</span><span class="lnt">11
215</span><span class="lnt">12
216</span><span class="lnt">13
217</span><span class="lnt">14
218</span><span class="lnt">15
219</span></code></pre></td>
220<td class="lntd">
221<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># 显示前 10 个基于 Nerd 的字体</span>
222</span></span><span class="line"><span class="cl"><span class="c1"># pacman -Ssq nerd-fonts | head -10</span>
223</span></span><span class="line"><span class="cl">
223ttf-nerd-fonts-symbols
224</span></span><span class="line"><span class="cl">ttf-nerd-fonts-symbols-mono
225</span></span><span class="line"><span class="cl">nerd-fonts-3270
226</span></span><span class="line"><span class="cl">nerd-fonts-agave
227</span></span><span class="line"><span class="cl">nerd-fonts-anonymous-pro
228</span></span><span class="line"><span class="cl">nerd-fonts-arimo
229</span></span><span class="line"><span class="cl">nerd-fonts-aurulent-sans-mono
230</span></span><span class="line"><span class="cl">nerd-fonts-bigblue-terminal
231</span></span><span class="line"><span class="cl">nerd-fonts-bitstream-vera-sans-mono
232</span></span><span class="line"><span class="cl">nerd-fonts-cascadia-code
233</span></span><span class="line"><span class="cl"><span class="c1"># 统计 Nerd 合成字体的总数</span>
234</span></span><span class="line"><span class="cl"><span class="c1"># pacman -Sl archlinuxcn | grep nerd-fonts | wc -l</span>
235</span></span><span class="line"><span class="cl"><span class="m">51</span>
236</span></span></code></pre></td></tr></table>
237</div>
238</div><p>为了能在字体里用上 Nerd fonts 图标,
239他们给 51 个字体都打上了来自 Nerd fonts 的补丁!</p>
240<p>当我们再想使用某个中文字体时,比如同时搭配
241思源黑体、anonymous-pro、Nerd font,岂不是要合成
242source-han-sans-otc-fonts-nerd-fonts-anonymous-pro?
243对了,别忘了还可以在合成字体里加入 emoji 字体。</p>
244<p>而 fontconfig 的缺点又是什么呢?后文会解释为什么 fontconfig 不能
245百分百命中想要的字体,特别是在两个浏览器 Chrome 和 Firefox 当中。</p>
246<h3 id="关于网页">关于网页</h3>
247<p>为了能在浏览器上显示想要的字体,不少人通过浏览器的扩展插件
248引入第三方的 CSS 样式,强制覆盖原网页的字体样式。
249这样做可能会破坏网页设计。因为有些网页是需要引入外部字体
250实现一些特殊效果的,这些字体的效果不依赖系统端的字体。
251但如果强制修改 CSS font-family 的话,就没办法使用这些字体了。
252除非完全不想关心网页设计师的想法,否则弊端比好处多。</p>
253<p>没必要引入 CSS 强制设置字体。对于网页的字体规则,
254浏览器也同样遵守 fontconfig 配置!
255所以我们可以通过 fontconfig 控制网页字体。</p>
256<p>现如今大部分网页的 CSS font-family 都是一个长长的串,
257里面包含了好多字体族名。但它一定会在这个串的最后面,
258包含一个通用字体族名。我们的 fontconfig 配置,
259就像上文中的配置那样,是在这个通用字体族名上进行操作的。</p>
260<h2 id="解决问题">解决问题</h2>
261<p>既然 Linux 有 fontconfig 这么好用的机制,不代表 fontconfig
262能很好的解决所有问题。这里有一些历史遗留问题,
263想解决它们好不是件容易的事情。</p>
264<h3 id="全角引号">全角引号</h3>
265<p>英文中的单引号有两种,<code>'</code>(U+0027) 和<code>’</code>(U+2019)。可能会觉得前一种出现
266在英文文本中,后一种出现在中文文本中,并且宽度和中文等宽。
267然而,英语世界中的一些人在英文文章中也是会使用后一种的。所以,
268字体在显示后一种引号的时候,究竟是和英文字母一样窄,还是
269该和中文字体等宽呢?如果在英文文章中显示成全宽字符则会显得
270突兀。</p>
271<p>比如,思源黑体其实也包含了拉丁字母的字形,
272可以完全使用思源黑体去显示西文。
273此时,后一种单引号的宽度会显示成中文字形的宽度。导致即使在全英文环境中,
274单引号也会突兀地在文本中过宽。</p>
275<p>同样地,<code>‘</code>(U+2018) <code>“</code>(U+201C) <code>”</code>(U+201D) 也有类似的情况。</p>
276<p>noto-cjk 官方项目在其 issue 上讨论了这个问题:
277<a href="https://github.com/googlefonts/noto-cjk/issues/5"target="_blank" rel="noopener noreferrer">Closed Full width punctuations U+2018, U+2019, U+201C and U+201D in Chinese
278</a>。
279在维基百科上也有相关内容:
280<a href="https://zh.wikipedia.org/zh-cn/%e6%92%87%e5%8f%b7"target="_blank" rel="noopener noreferrer">撇号</a>。</p>
281<p>我们的目标是在不同语言环境下字形会有所区别,让引号只在中文文本中全宽。
282用该 HTML 片段测试字体</p>
283<div class="highlight"><div class="chroma">
284<table class="lntable"><tr><td class="lntd">
285<pre tabindex="0" class="chroma"><code><span class="lnt">1
286</span><span class="lnt">2
287</span><span class="lnt">3
288</span><span class="lnt">4
289</span></code></pre></td>
290<td class="lntd">
291<pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;font-family:sans&#34;</span> <span class="p">&gt;</span>
292</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">p</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;en-za&#34;</span><span class="p">&gt;</span>lang=en-us, rydesun’s blog<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
293</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">p</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;zh-cn&#34;</span><span class="p">&gt;</span>lang=zh-cn, 中文‘引号’问题<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
294</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
295</span></span></code></pre></td></tr></table>
296</div>
297</div><p><a href="/raw/fontconfig.html#%e5%bc%95%e5%8f%b7">用你的浏览器在线测试。</a>效果图:</p>
298
299
300
301<image src="/images/font_quote.8af1aaf6db80a54b1234b2eb73bb9f2334cce9d8949645c1c8ca796bf9c5f6af.png"
302  id=""
303  width="280"
304  height="85"class="auto-dark"alt="引号的效果对比图"
305  style="height: auto;"
306>
307
308<p>所以,在没有有效配置的情况下,当使用中文字体去显示英文文本时,
309会错误地提供全宽引号。
310更纱黑体提供了一个折衷的办法,分别提供两个字体族名,
311Sarasa Gothic 使用全角引号,Sarasa UI 使用和字母一个宽度的引号。
312你可以根据实际需要选择字体族名。来自 Sarasa Gothic 的 README:</p>
313<pre tabindex="0"><code>Style dimension
314    Latin/Greek/Cyrillic character set being Inter
315        Quotes (“”) are full width —— Gothic
316        Quotes (“”) are narrow —— UI
317</code></pre><p>由于 fontconfig 是可以根据语言来灵活选择字体的,
318在后文讲 fontconfig 配置的时候,我们再来
319处理这个问题。</p>
320<h3 id="异体字">异体字</h3>
321<p>我在这里说的异体字,可不是简体和繁体的区别。Noto Sans CJK 中
322的异体字,是在 <strong>相同的</strong> Unicode 码位下,不同的语言会使用不同的字形。
323这可不是「卫」和「衛」的区别,也不是诸如中文的「传」和日语汉字的「伝」
324的区别,因为它们本来就分属于不同的 Unicode 码位。
325而是说,同一个 Unicode 码位的汉字在字形上有微妙的不同。</p>
326<p>没错,这类似于上文说到的引号问题:占据同一个 Unicode 码位,但却可以有不同
327字形。</p>
328<p>用该 HTML 片段测试字体,在不同语言环境下字形会有所区别。</p>
329<div class="highlight"><div class="chroma">
330<table class="lntable"><tr><td class="lntd">
331<pre tabindex="0" class="chroma"><code><span class="lnt">1
332</span><span class="lnt">2
333</span><span class="lnt">3
334</span><span class="lnt">4
335</span><span class="lnt">5
336</span><span class="lnt">6
337</span><span class="lnt">7
338</span><span class="lnt">8
339</span></code></pre></td>
340<td class="lntd">
341<pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;font-family:sans&#34;</span><span class="p">&gt;</span>
342</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>遍角次亮采之门 默认<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
343</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">p</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;zh-cn&#34;</span><span class="p">&gt;</span>遍角次亮采之门 中文(大陆) lang=zh-cn<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
344</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">p</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;zh-tw&#34;</span><span class="p">&gt;</span>遍角次亮采之门 中文(台湾) lang=zh-tw<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
345</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">p</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;zh-hk&#34;</span><span class="p">&gt;</span>遍角次亮采之门 中文(香港) lang=zh-hk<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
346</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">p</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;ja&#34;</span><span class="p">&gt;</span>遍角次亮采之门 日文 lang=ja<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
347</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">p</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;ko&#34;</span><span class="p">&gt;</span>遍角次亮采之门 韩文 lang=ko<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
348</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
349</span></span></code></pre></td></tr></table>
350</div>
351</div><p><a href="/raw/fontconfig.html#%e5%bc%82%e4%bd%93%e5%ad%97">用你的浏览器在线测试</a>。效果图:</p>
352
353
354
355<image src="/images/font_glyph_variants.3e1870ca27af61652dd2cac679db19939f869a
3557342b794c9273ffee9a7fc1189.png"
356  id=""
357  width="250"
358  height="280"class="auto-dark"alt="字形的效果对比图"
359  style="height: auto;"
360>
361
362<p>如果你的浏览器显示的效果和上面的效果图不一致,
363并且「默认」那一行 (默认的意思是没有指定语言的情况)
364不是你想要的默认字形,可能是因为缺少该字体或者没有成功配置 fontconfig。</p>
365<p>Arch Linux 用户注意了!如果只选择安装 adobe-source-han-sans-<strong>cn</strong>-fonts
366(注意是 cn),
367是无法正确显示异体字的,因为它是思源黑体的一个子集 (subset),只有中国大陆字形,
368去掉了上面说到的异体字。当然,也仅仅是失去了少数这些特殊的异体字罢了,
369繁体字、日文汉字还是正常包含的。</p>
370<p>其实大部分中文字体都没有该功能。你可能好奇思源黑体是怎么做到的。
371其实这是一个字体特性,字体文件会在内部携带 GSUB 表 (Glyph Substitution Table),
372实现从 locl GSUB 中根据特定语言查询到对应的字形。
373完整版的思源黑体是具备该特性的。
374所以想要包含上文提到的那些异体字,
375应该选择安装 adobe-source-han-sans-<strong>otc</strong>-fonts 或者 noto-sans-cjk。</p>
376<p>既然如此,为什么还会存在 adobe-source-han-sans-<strong>cn</strong>-fonts (包名带 cn 的那个版本)?
377那是给完全不关心这些异体字的用户推出的版本,在种语言环境中只显示中国大陆字形。
378当然大部分繁体字和日文汉字还是正常显示的,毕竟占据相同 Unicode 码位
379的异体字只占很小一部分。</p>
380<p>然而真实情况是,不少人安装 adobe-source-han-sans-<strong>otc</strong>-fonts
381或者 noto-sans-cjk 后,抱怨一些字形怎么显示异常呀?然后
382被告知安装 adobe-source-han-sans-<strong>cn</strong>-fonts 后就正常了。
383当然会显示正常了,因为把异体字给丢掉了嘛!
384无论是 Adobe 的 adobe-source-han-sans-<strong>otc</strong>-fonts
385还是 Google 的 noto-sans-cjk,默认使用日文异体字。
386但对于中文用户来说,默认显示日文异体字太奇怪了。</p>
387<p>其实完全可以在保留异体字的情况下,让它默认显示中国大陆字形;
388只在特定语言下显示异体字,比如用浏览器查看一个日文页面。
389所以需要正确配置 fontconfig,这也是本文的目的之一。
390在后文的 <a href="#%e6%80%9d%e6%ba%90%e5%ad%97%e4%bd%93">思源字体</a> 一节,我们再来看看思源黑体的版本。</p>
391<h3 id="中文字体的西文部分">中文字体的西文部分</h3>
392<p>如果去观察 Noto Sans CJK 这个中文字体,
393会发现它的西文部分的字形其实和 Noto Sans 不一样,虽然它们都以 Noto 自称。</p>
394<p>除了上面说到的引号问题,中文字体中还存在什么问题呢?那就是
395中文字体携带的英文字符有可能十分糟糕,特别是 Windows 自带的 SimHei,
396也就是中易黑体,它的英文相当糟糕。
397另外,微软雅黑的字重实在是太少了,对于设计师来说很不友好。而各种流行的
398英文字体支持很多字重。</p>
399<p>可以注意到著名的 bootstrap 也遭遇到这个问题,当他们决定在 font-family 中
400使用 system-ui,后来又不得不去掉 system-ui:
401<a href="https://github.com/twbs/bootstrap/issues/22328"target="_blank" rel="noopener noreferrer">Do not let system-ui come before &ldquo;Segoe UI&rdquo; in font-family—or
402remove it from the font stack altogether
403</a>。
404因为 system-ui 这个 CSS font-family 值会让浏览器直接调用系统界面所使用
405的字体去渲染。但对于 Windows 简中用户来说,
406英文字体渲染这块使用的是微软雅黑,甚至可能是宋体 (中易宋体),这是网页
407设计师不愿意看到的结果。它会让简体中文用户看到非预期的、渲染糟糕的英文
408字符。虽然在 Linux 上我们没这个烦恼,但是想改动它的话当然是能做到的,
409这对 fontconfig 来说小事一桩,
410详见后文 <a href="#%e7%ac%ac%e5%9b%9b%e6%ad%a5-%e8%a6%86%e7%9b%96%e8%a5%bf%e6%96%87%e5%ad%97%e4%bd%93">第四步:覆盖西文字体</a>。</p>
411<h2 id="字体比较与选择">字体比较与选择</h2>
412<p>习惯上把中文字体的黑体和无衬线归为一类,把宋体和è
412¡¬çº¿å½’为一类。至于等宽字体,
413是出于排版的需要,规定每个字符是全宽或者半宽,没有规定是否必有衬线。
414可以选择宋体和衬线西文作为等宽字体,
415也可以选择黑体和无衬线西文。
416只要能让西文等宽,并且宽度是中文字符的一半 (HW) 即可。
417通常使用黑体中文和无衬线西文较为常见。</p>
418<p>宋体,日语称为明朝体,Mincho;港台称为明體。
419所以它们是一个意思。</p>
420<p>黑体,在日语中称为 ゴシック 或者 Gothic。注意它不是哥特式风格的意思。</p>
421<p>知乎:<a href="https://www.zhihu.com/question/31772770"target="_blank" rel="noopener noreferrer">为什么日本人称『黑体』为『哥特体』?</a></p>
422<h3 id="编程字体">编程字体</h3>
423<p>对于经常写程序的人来说,
424会选择一款合适的等宽字体作为编程字体和虚拟终端下的字体。有太多可供选择了,
425Source Code Pro,Consolas,Menlo……
426还有像 <a href="https://github.com/tonsky/FiraCode"target="_blank" rel="noopener noreferrer">Fira Code</a>
427这样以连字 (ligature)
428特性为主的编程字体。</p>
429<p>我比较推崇 <a href="https://github.com/be5invis/Iosevka"target="_blank" rel="noopener noreferrer">Iosevka</a>,
430它可不是一个普通的等宽字体,
431而是一个高度可定制化的字体,你可以自己微调字形,
432再进行编译,从而制作出独特的编程字体,
433不用再眼馋其他等宽字体的特性了。可以看项目 README 中的
434<a href="https://github.com/be5invis/Iosevka#customized-build"target="_blank" rel="noopener noreferrer">Customized Build</a> 一节,
435提供了丰富的自定义项。
436比如我自己的 <a href="https://github.com/rydesun/iosevka-custom"target="_blank" rel="noopener noreferrer">rydesun/iosevka-custom</a>,
437在文件<code>private-build-plans.toml</code>中配置字体,
438再用<code>makepkg</code>编译打包成属于我自己的 Arch 包。
439像我就关闭了连字特性,我不喜欢在代码中看到连字。</p>
440<p>另外,你可能还会想使用图标字体。
441在虚拟终端和一些系统界面 (窗管插件栏) 中使用图标字体是一个很好的想法。
442有好些个值得推荐的图标字体,比如 <a href="https://fontawesome.com/"target="_blank" rel="noopener noreferrer">Font Awesome</a>,
443<a href="http://ionicons.com/"target="_blank" rel="noopener noreferrer">Ionicons</a>。
444而流行的 <a href="https://www.nerdfonts.com/"target="_blank" rel="noopener noreferrer">Nerd Fonts</a> 则整合了好多个图标字体。
445对我来说,<a href="https://github.com/ryanoasis/vim-devicons"target="_blank" rel="noopener noreferrer">vim-devicons</a> 和它的搭配是必不可少的,
446两个项目都来自同一个作者。
447Arch 用户可以安装 ttf-nerd-fonts-symbols 或者 ttf-nerd-fonts-symbols-mono 就能拥有它。</p>
448<h3 id="思源字体">思源字体</h3>
449<p>思源字体到底有多少个变体呀?现在让我们来捋一捋 😃</p>
450<p>就以 Arch Linux 仓库和 AUR 为例。
451上游拆分了多少字体,Arch Linux 仓库里就打包了多少个思源黑体:</p>
452<pre tabindex="0"><code>adobe-source-han-sans-cn-fonts
453adobe-source-han-sans-hk-fonts
454adobe-source-han-sans-jp-fonts
455adobe-source-han-sans-kr-fonts
456adobe-source-han-sans-tw-fonts
457</code></pre><p>好家伙,每种语言来一份。
458其实它们对应了官方项目 README
459中 <a href="https://github.com/adobe-fonts/source-han-sans/tree/release/#region-specific-subset-otfs"target="_blank" rel="noopener noreferrer">Region-specific Subset OTFs</a>
460这一节所说的版本。</p>
461<p>这还只是黑体部分,
462再来看看到宋体,
463adobe-source-han-<strong>serif-otc</strong>-fonts 和它的 subset
464(小提示:思源宋体没有专门制定 HK 版本。)</p>
465<pre tabindex="0"><code>adobe-source-han-serif-cn-fonts
466adobe-source-han-serif-jp-fonts
467adobe-source-han-serif-kr-fonts
468adobe-source-han-serif-tw-fonts
469</code></pre><p>等宽字体呢?</p>
470<p>其中在 adobe-source-han-<strong>sans</strong> 当中,已经包含了等宽字体家族名,
471它是以 HW 结尾的,代表西文字符是中文一半的宽度。
472至于 AUR 和 archlinuxcn 社区仓库打包的 adobe-source-han-<strong>mono-otc</strong>-fonts,
473以及它的每种语言的 subset (又开始重复了)</p>
474<pre tabindex="0"><code>adobe-source-han-mono-cn-fonts
475adobe-source-han-mono-hk-fonts
476adobe-source-han-mono-jp-fonts
477adobe-source-han-mono-kr-fonts
478adobe-source-han-mono-tw-fonts
479</code></pre><p>上游来自 adobe-fonts/source-han-<strong>mono</strong>,这是另外一个项目,纯属 Adobe 员工的个人项目 (
480<a href="https://github.com/adobe-fonts/source-han-mono/issues/1#issuecomment-541322936"target="_blank" rel="noopener noreferrer">
480作者的解释</a>),
481它是把西文部分替换成了 Source Code Pro。
482既然前面提到,adobe-source-han-<strong>sans</strong> 包中是带有 HW 这类等宽
483变体的,为什么还要有带有 Source Code Pro 这个版本呢?
484显然是因为喜欢合成字体的人们。
485在有 fontconfig 的情况下这是不必要的,
486因为我们可以用 fontconfig 制定替换规则。</p>
487<p>如果你不关心异体字,那么偷懒的做法是选择 adobe-source-han-sans-cn-fonts,它来自官方 README 小节
488<a href="https://github.com/adobe-fonts/source-han-sans/tree/release/#region-specific-subset-otfs"target="_blank" rel="noopener noreferrer">Region-specific Subset OTFs</a>。
489因为是 subset,所以想要完整版的话,
490就要选择 adobe-source-han-sans-<strong>otc</strong>-fonts,
491它来自官方 README 小节
492<a href="https://github.com/adobe-fonts/source-han-sans/tree/release/#otcs"target="_blank" rel="noopener noreferrer">OTCs</a>。
493其实在没有 fontconfig 的情况下,特别是 Windows 上,应该选择
494<a href="https://github.com/adobe-fonts/source-han-sans/tree/release/#language-specific-otfs"target="_blank" rel="noopener noreferrer">Language-specific OTFs</a>
495一节的版本,它同样包含完整版的异体字,但默认语言不是日文,而是让我们选择。
496可惜 Arch Linux 社区仓库没有打包它们,所以我们需要在 OTCs 版本上,用 fontconfig 设置默认语言版本。
497至于那个 <a href="https://github.com/adobe-fonts/source-han-sans/tree/release/#super-otc"target="_blank" rel="noopener noreferrer">Super OTC</a>,
498它是把多个字重再合并到一个文件中的「便携版」,必要性不大,所以社区仓库也没有打包它。以上说的是思源黑体。思源宋体同理,不再重复阐述。</p>
499<h3 id="更纱黑体">更纱黑体</h3>
500<p>更纱黑体是由思源黑体和西文字体 Iosevka 整合而来的,或者说,它把
501思源黑体的西文部分替换成了 Iosevka 这个字体。
502更纱黑体的作者就是 Iosevka 的作者;
503该项目的 README 第一句话就指明了:</p>
504<pre tabindex="0"><code>This is SARASA GOTHIC,
505a CJK programming font based on Iosevka and Source Han Sans.
506</code></pre><p>由于思源黑体的西文
507部分不是很全面,所以更纱黑体也算是扩充了一部分字形。另外,
508更纱黑体在思源黑体的中文字形上做了一些调整。
509我不是很清楚它具体做了哪方面的调整。
510但我认为没必要使用更纱黑体,起码在 Linux 上没这个必要,
511想要整合多个字体靠 fontconfig 就可以做到。</p>
512<h3 id="我的选择">我的选择</h3>
513<ul>
514<li>无衬线:西文 Noto Sans,中文 Noto Sans CJK</li>
515<li>衬线:西文 Noto Serif,中文 Noto Serif CJK</li>
516<li>等宽:西文 Iosevka,中文 Noto Sans Mono CJK</li>
517</ul>
518<p>西文字体 Noto Sans / Noto Serif 来自于软件包<code>noto-fonts</code>,
519中文字体 Noto Sans CJK / Noto Serif CJK / Noto Sans Mono CJK
520来自于软件包<code>noto-fonts-cjk</code>。
521Arch Linux 上只装这两个包就行了,就足以覆盖世界上
522绝大部分的字形了。由于 Noto CJK 是 Google 对思源字体
523的 rebrand,它们是完全一样的,所以我在这里没有选择以 Adobe 版本
524为主打包的方式。</p>
525<p>关于 emoji,我选择了 Twitter 推出的字体 Twemoji。</p>
526<ul>
527<li>ttf-twemoji</li>
528</ul>
529<p>另外,少不了人见人爱的图标字体 Nerd Fonts。</p>
530<ul>
531<li>ttf-nerd-fonts-symbols</li>
532</ul>
533<h2 id="基本思路">基本思路</h2>
534<p>絮絮叨叨半篇文章,fontconfig 的配置究竟长什么样呀!</p>
535<p>现在终于可以进入正式环节了,但我却想把这部分内容压缩得尽可能短,毕竟
536越简单的配置越容易理解和维护。这里还是建议先看完上一篇文章,
537因为一些原理,本文不会再重复。
538如果想深入到 fontconfig 的配置中去,最好是先了解它。</p>
539<p>基本思路只有一个,设置默认字体为通用字体族名。</p>
540<p>不要在程序设置中指定使用思源黑体或者更纱黑体等等字体,
541毕竟你一次只能指定一个字体。
542合理的做法是在设置中指定程序使用通用字体族名:
543sans-serif,serif,monospace。
544这样做会让程序使用 fontconfig 提供的 fallback 列表,
545也就是 font pattern,里面包含我们想要优先使用的所有字体。
546比如在虚拟终端的配置使用 monospace,而不是某个具体的等宽字体。
547大部分虚拟终端本来默认就是使用 monospace 的,所以你无需
548修改它。如果修改过,请复原默认值。</p>
549<p>姑且认为这是第零步吧。</p>
550<p>最简单的配置文件路径是<code>~/.config/fontconfig/fonts.conf</code>,我们的配置添加
551到这个文件中。</p>
552<div class="highlight"><div class="chroma">
553<table class="lntable"><tr><td class="lntd">
554<pre tabindex="0" class="chroma"><code><span class="lnt">1
555</span><span class="lnt">2
556</span><span class="lnt">3
557</span><span class="lnt">4
558</span><span class="lnt">5
559</span><span class="lnt">6
560</span><span class="lnt">7
561</span></code></pre></td>
562<td class="lntd">
563<pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="cp">&lt;?xml version=&#34;1.0&#34;?&gt;</span>
564</span></span><span class="line"><span class="cl"><span class="cp">&lt;!DOCTYPE fontconfig SYSTEM &#34;urn:fontconfig:fonts.dtd&#34;&gt;</span>
565</span></span><span class="line"><span class="cl"><span class="nt">&lt;fontconfig&gt;</span>
566</span></span><span class="line"><span class="cl">
567</span></span><span class="line"><span class="cl"><span class="c">&lt;!-- 实际内容 --&gt;</span>
568</span></span><span class="line"><span class="cl">
569</span></span><span class="line"><span class="cl"><span class="nt">&lt;/fontconfig&gt;</span>
570</span></span></code></pre></td></tr></table>
571</div>
572</div><p>实际配置内容被包裹在其中。我在 gist 上提供了一份
573<a href="https://gist.github.com/rydesun/cbeab3a6d7b9ccf3c47d890c7caa3a11"target="_blank" rel="noopener noreferrer">完整的示例配置</a>,
574作为参考。</p>
575<h2 id="第一步设置默认字体">第一步:设置默认字体</h2>
576<div class="highlight"><div class="chroma">
577<table class="lntable"><tr><td class="lntd">
578<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
579</span><span class="lnt"> 2
580</span><span class="lnt"> 3
581</span><span class="lnt"> 4
582</span><span class="lnt"> 5
583</span><span class="lnt"> 6
584</span><span class="lnt"> 7
585</span><span class="lnt"> 8
586</span><span class="lnt"> 9
587</span><span class="lnt">10
588</span><span class="lnt">11
589</span><span class="lnt">12
590</span><span class="lnt">13
591</span><span class="lnt">14
592</span><span class="lnt">15
593</span><span class="lnt">16
594</span><span class="lnt">17
595</span><span class="lnt">18
596</span><span class="lnt">19
597</span><span class="lnt">20
598</span><span class="lnt">21
599</span><span class="lnt">22
600</span><span class="lnt">23
601</span><span class="lnt">24
602</span><span class="lnt">25
603</span><span class="lnt">26
604</span><span class="lnt">27
605</span><span class="lnt">28
606</span><span class="lnt">29
607</span><span class="lnt">30
608</span><span class="lnt">31
609</span><span class="lnt">32
610</span><span class="lnt">33
611</span><span class="lnt">34
612</span><span class="lnt">35
613</span><span class="lnt">36
614</span><span class="lnt">37
615</span><span class="lnt">38
616</span><span class="lnt">39
617</span><span class="lnt">40
618</span><span class="lnt">41
619</span><span class="lnt">42
620</span><span class="lnt">43
621</span><span class="lnt">44
622</span><span class="lnt">45
623</span></code></pre></td>
624<td class="lntd">
625<pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="c">&lt;!-- Default system-ui fonts --&gt;</span>
626</span></span><span class="line"><span class="cl"><span class="nt">&lt;match</span> <span class="na">target=</span><span class="s">&#34;pattern&#34;</span><span class="nt">&gt;</span>
627</span></span><span class="line"><span class="cl">  <span class="nt">&lt;test</span> <span class="na">name=</span><span class="s">&#34;family&#34;</span><span class="nt">&gt;</span>
628</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>system-ui<span class="nt">&lt;/string&gt;</span>
629</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/test&gt;</span>
630</span></span><span class="line"><span class="cl">  <span class="nt">&lt;edit</span> <span class="na">name=</span><span class="s">&#34;family&#34;</span> <span class="na">mode=</span><span class="s">&#34;prepend&#34;</span> <span class="na">binding=</span><span class="s">&#34;strong&#34;</span><span class="nt">&gt;</span>
631</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>sans-serif<span class="nt">&lt;/string&gt;</span>
632</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/edit&gt;</span>
633</span></span><span class="line"><span class="cl"><span class="nt">&lt;/match&gt;</span>
634</span></span><span class="line"><span class="cl">
635</span></span><span class="line"><span class="cl"><span class="c">&lt;!-- Default sans-serif fonts--&gt;</span>
636</span></span><span class="line"><span class="cl"><span class="nt">&lt;match</span> <span class="na">target=</span><span class="s">&#34;pattern&#34;</span><span class="nt">&gt;</span>
637</span></span><span class="line"><span class="cl">  <span class="nt">&lt;test</span> <span class="na">name=</span><span class="s">&#34;family&#34;</span><span class="nt">&gt;</span>
638</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>sans-serif<span class="nt">&lt;/string&gt;</span>
639</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/test&gt;</span>
640</span></span><span class="line"><span class="cl">  <span class="nt">&lt;edit</span> <span class="na">name=</span><span class="s">&#34;family&#34;</span> <span class="na">mode=</span><span class="s">&#34;prepend&#34;</span> <span class="na">binding=</span><span class="s">&#34;strong&#34;</span><span class="nt">&gt;</span>
641</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Noto Sans CJK SC<span class="nt">&lt;/string&gt;</span>
642</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Noto Sans<span class="nt">&lt;/string&gt;</span>
643</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Twemoji<span class="nt">&lt;/string&gt;</span>
644</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/edit&gt;</span>
645</span></span><span class="line"><span class="cl"><span class="nt">&lt;/match&gt;</span>
646</span></span><span class="line"><span class="cl">
647</span></span><span class="line"><span class="cl"><span class="c">&lt;!-- Default serif fonts--&gt;</span>
648</span></span><span class="line"><span class="cl"><span class="nt">&lt;match</span> <span class="na">target=</span><span class="s">&#34;pattern&#34;</span><span class="nt">&gt;</span>
649</span></span><span class="line"><span class="cl">  <span class="nt">&lt;test</span> <span class="na">name=</span><span class="s">&#34;family&#34;</span><span class="nt">&gt;</span>
650</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>serif<span class="nt">&lt;/string&gt;</span>
651</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/test&gt;</span>
652</span></span><span class="line"><span class="cl">  <span class="nt">&lt;edit</span> <span class="na">name=</span><span class="s">&#34;family&#34;</span> <span class="na">mode=</span><span class="s">&#34;prepend&#34;</span> <span class="na">binding=</span><span class="s">&#34;strong&#34;</span><span class="nt">&gt;</span>
653</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Noto Serif CJK SC<span class="nt">&lt;/string&gt;</span>
654</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Noto Serif<span class="nt">&lt;/string&gt;</span>
655</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Twemoji<span class="nt">&lt;/string&gt;</span>
656</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/edit&gt;</span>
657</span></span><span class="line"><span class="cl"><span class="nt">&lt;/match&gt;</span>
658</span></span><span class="line"><span class="cl">
659</span></span><span class="line"><span class="cl"><span class="c">&lt;!-- Default monospace fonts--&gt;</span>
660</span></span><span class="line"><span class="cl"><span class="nt">&lt;match</span> <span class="na">target=</span><span class="s">&#34;pattern&#34;</span><span class="nt">&gt;</span>
661</span></span><span class="line"><span class="cl">  <span class="nt">&lt;test</span> <span class="na">name=</span><span class="s">&#34;family&#34;</span><span class="nt">&gt;</span>
662</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>monospace<span class="nt">&lt;/string&gt;</span>
663</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/test&gt;</span>
664</span></span><span class="line"><span class="cl">  <span class="nt">&lt;edit</span> <span class="na">name=</span><span class="s">&#34;family&#34;</span> <span class="na">mode=</span><span class="s">&#34;prepend&#34;</span> <span class="na">binding=</span><span class="s">&#34;strong&#34;</span><span class="nt">&gt;</span>
665</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Noto Sans Mono CJK SC<span class="nt">&lt;/string&gt;</span>
666</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>
666Symbols Nerd Font<span class="nt">&lt;/string&gt;</span>
667</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Twemoji<span class="nt">&lt;/string&gt;</span>
668</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/edit&gt;</span>
669</span></span><span class="line"><span class="cl"><span class="nt">&lt;/match&gt;</span>
670</span></span></code></pre></td></tr></table>
671</div>
672</div><p>对 system-ui,sans-serif,serif,monospace 设置优先显示的字体。
673在这里我让 system-ui 默认为无衬线。
674注意,system-ui 必须在最前。
675由于 fontconfig 对 font pattern 的操作是按顺序执行的,所以必须先让 system-ui 能
676优先以 sans-serif 显示,然后才是对 sans-serif 的操作。</p>
677<p>所有的 Noto CJK 字体都以 SC 结尾,因为我希望在没指定语言的默认情况下,
678以简体中文显示中文字形。</p>
679<p>问题来了,为什么我要用属性<code>binding=&quot;strong&quot;</code>?这和 fontconfig 的绑定特性有关。
680在对 font pattern 的编辑处理过后,fontconfig 会再对 font pattern 进行排序;
681font pattern 中的强绑定字体会移动到前面,弱绑定字体会移动到后面。
682也就是说,f1(s) f2(w) f3(w) f4(s) 这种 font pattern 会变成 f1(s) f4(s) f2(w) f3(w)。
683(s) 代表强绑定字体,(w) 代表弱绑定字体。不仅如此,fontconfig 还要对
684弱绑定字体再次排序,如果 f3(w) 这个字体支持 font pattern 中传入的语言参数,
685它将被移动到 f2(w) 前面。所以最终结果是 f1(s) f4(s) f3(w) f2(w)。</p>
686<p>这也就是为什么很多人说,明明在 fontconfig 中设置好的字体顺序,结果还是乱了。
687你期望 fontconfig 编辑过后的字体顺序是 f1(s) f2(w) f3(w) f4(s),但最后变成了
688f1(s) f4(s) f3(w) f2(w)。
689其实是因为没有注意到 fontconfig 的强弱绑定特性。
690所以,在我们配置 fontconfig 的时候,应该统一使用强绑定,
691也就是<code>binding=&quot;strong&quot;</code>,让自己的规则优先于系统端的默认配置。</p>
692<p>当网页指定了页面语言,Firefox 和 Chrome 浏览器是怎么处理它的呢?</p>
693<p>Firefox 只会对三大通用字体族名 (sans-serif,serif,monospace)
694传递页面语言给 fontconfig,其他字体则是传环境变量中的 LANG。
695另外,Firefox 会把 system-ui 当作普通的字族名传递给 fontconfig,
696而没有特殊处理它。(TODO 待确认:Firefox 在面对通用字体族名时,
697只会取配置中的前 3 个字体?)</p>
698<p>Chrome 完全不传语言给 fontconfig。与 Firefox 不一样,Chrome
699会特殊对待 system-ui,从 GTK 设置那里直接拿来字体。</p>
700<h2 id="第二步按语言选择异体字">第二步:按语言选择异体字</h2>
701<p>显示异体字有两种方式:</p>
702<ul>
703<li>
704<p>在 fontconfig 的字体匹配阶段,通过语言选中该语言对应的字体族名。</p>
705</li>
706<li>
707<p>在字体渲染阶段,通过字体文件带有的 GSUB 表根据语言选择字形。</p>
708</li>
709</ul>
710<p>为了能让程序或者 Web 页面能在 zh-HK 语言环境中使用 Noto Sans CJK HK,可以这样做:</p>
711<div class="highlight"><div class="chroma">
712<table class="lntable"><tr><td class="lntd">
713<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
714</span><span class="lnt"> 2
715</span><span class="lnt"> 3
716</span><span class="lnt"> 4
717</span><span class="lnt"> 5
718</span><span class="lnt"> 6
719</span><span class="lnt"> 7
720</span><span class="lnt"> 8
721</span><span class="lnt"> 9
722</span><span class="lnt">10
723</span><span class="lnt">11
724</span><span class="lnt">12
725</span></code></pre></td>
726<td class="lntd">
727<pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="nt">&lt;match</span> <span class="na">target=</span><span class="s">&#34;pattern&#34;</span><span class="nt">&gt;</span>
728</span></span><span class="line"><span class="cl">  <span class="nt">&lt;test</span> <span class="na">name=</span><span class="s">&#34;lang&#34;</span><span class="nt">&gt;</span>
729</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>zh-HK<span class="nt">&lt;/string&gt;</span>
730</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/test&gt;</span>
731</span></span><span class="line"><span class="cl">  <span class="nt">&lt;test</span> <span class="na">name=</span><span class="s">&#34;family&#34;</span><span class="nt">&gt;</span>
732</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Noto Sans CJK SC<span class="nt">&lt;/string&gt;</span>
733</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/test&gt;</span>
734</span></span><span class="line"><span class="cl">  <span class="nt">&lt;edit</span> <span class="na">name=</span><span class="s">&#34;family&#34;</span> <span class="na">binding=</span><span class="s">&#34;strong&#34;</span><span class="nt">&gt;</span>
735</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Noto Sans CJK HK<span class="nt">&lt;/string&gt;</span>
736</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/edit&gt;</span>
737</span></span><span class="line"><span class="cl"><span class="nt">&lt;/match&gt;</span>
738</span></span><span class="line"><span class="cl"><span class="c">&lt;!-- 另外请再重复 zh-TW、ja、ko --&gt;</span>
739</span></span></code></pre></td></tr></table>
740</div>
741</div><p>在字体匹配时,将 Noto Sans CJK SC 替换成 Noto Sans CJK HK。
742除了 zh-HK,你还需要照葫芦画瓢分别指定 zh-TW、ja、ko,
743以及对宋体和等宽字体进行重复的步骤。
744在此我就不重复了。</p>
745<p>
745PS. 在用 FC_DEBUG 查看 fontconfig 的调试信息时,
746程序传递给 fontconfig 的语言参数,显示在 lang 一行而不是 familylang。
747familylang 是指一个字体它的族名的语言版本,比如简中版思源黑体的字体
748族名有「思源黑体」(zh-cn)、「Source Han Sans SC」(en),这两个字体
749族名指向同一个字体。</p>
750<h2 id="第三步替换任意字体">第三步:替换任意字体</h2>
751<p>当系统里已经安装了一些不需要的字体,但又不想删除或者屏蔽它怎么办呢?
752替换掉 font pattern 就可以了。我发现在安装完 Arch Linux 后,
753存在依赖 adobe-source-code-pro-fonts,它包含了 Source Code Variable
754和 Source Code Pro 这两个字体,但我不想使用它们,所以可以直接替换掉</p>
755<div class="highlight"><div class="chroma">
756<table class="lntable"><tr><td class="lntd">
757<pre tabindex="0" class="chroma"><code><span class="lnt">1
758</span><span class="lnt">2
759</span><span class="lnt">3
760</span><span class="lnt">4
761</span><span class="lnt">5
762</span><span class="lnt">6
763</span><span class="lnt">7
764</span><span class="lnt">8
765</span></code></pre></td>
766<td class="lntd">
767<pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="nt">&lt;match</span> <span class="na">target=</span><span class="s">&#34;pattern&#34;</span><span class="nt">&gt;</span>
768</span></span><span class="line"><span class="cl">  <span class="nt">&lt;test</span> <span class="na">name=</span><span class="s">&#34;family&#34;</span> <span class="na">compare=</span><span class="s">&#34;contains&#34;</span><span class="nt">&gt;</span>
769</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Source Code<span class="nt">&lt;/string&gt;</span>
770</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/test&gt;</span>
771</span></span><span class="line"><span class="cl">  <span class="nt">&lt;edit</span> <span class="na">name=</span><span class="s">&#34;family&#34;</span> <span class="na">binding=</span><span class="s">&#34;strong&#34;</span><span class="nt">&gt;</span>
772</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Iosevka Term<span class="nt">&lt;/string&gt;</span>
773</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/edit&gt;</span>
774</span></span><span class="line"><span class="cl"><span class="nt">&lt;/match&gt;</span>
775</span></span></code></pre></td></tr></table>
776</div>
777</div><p>注意我用了<code>compare=&quot;contains&quot;</code>直接匹配这两个字体,
778然后改成了我需要的 Iosevka Term。</p>
779<h2 id="第四步覆盖西文字体">第四步:覆盖西文字体</h2>
780<p>让西文字体出现在 font pattern 中的中文字体前面,就能让程序优先
781使用我们指定的西文字体了,同时也解决了引号问题。
782在此我们需要继续使用强绑定。</p>
783<div class="highlight"><div class="chroma">
784<table class="lntable"><tr><td class="lntd">
785<pre tabindex="0" class="chroma"><code><span class="lnt">1
786</span><span class="lnt">2
787</span><span class="lnt">3
788</span><span class="lnt">4
789</span><span class="lnt">5
790</span><span class="lnt">6
791</span><span class="lnt">7
792</span><span class="lnt">8
793</span><span class="lnt">9
794</span></code></pre></td>
795<td class="lntd">
796<pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="nt">&lt;match</span> <span class="na">target=</span><span class="s">&#34;pattern&#34;</span><span class="nt">&gt;</span>
797</span></span><span class="line"><span class="cl">  <span class="nt">&lt;test</span> <span class="na">name=</span><span class="s">&#34;family&#34;</span> <span class="na">compare=</span><span class="s">&#34;contains&#34;</span><span class="nt">&gt;</span>
798</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Noto Sans CJK<span class="nt">&lt;/string&gt;</span>
799</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/test&gt;</span>
800</span></span><span class="line"><span class="cl">  <span class="nt">&lt;edit</span> <span class="na">name=</span><span class="s">&#34;family&#34;</span> <span class="na">mode=</span><span class="s">&#34;prepend&#34;</span> <span class="na">binding=</span><span class="s">&#34;strong&#34;</span><span class="nt">&gt;</span>
801</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Noto Sans<span class="nt">&lt;/string&gt;</span>
802</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/edit&gt;</span>
803</span></span><span class="line"><span class="cl"><span class="nt">&lt;/match&gt;</span>
804</span></span><span class="line"><span class="cl"><span class="c">&lt;!-- 糟糕!中文文本的引号不是全角的 --&gt;</span>
805</span></span></code></pre></td></tr></table>
806</div>
807</div><p>慢着!这样岂不是在中文环境中使用西文字体,包括英文字符宽度的引号?
808确实有这个问题。所以,把上面的配置改成:</p>
809<div class="highlight"><div class="chroma">
810<table class="lntable"><tr><td class="lntd">
811<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
812</span><span class="lnt"> 2
813</span><span class="lnt"> 3
814</span><span class="lnt"> 4
815</span><span class="lnt"> 5
816</span><span class="lnt"> 6
817</span><span class="lnt"> 7
818</span><span class="lnt"> 8
819</span><span class="lnt"> 9
820</span><span class="lnt">10
821</span><span class="lnt">11
822</span><span class="lnt">12
823</span></code></pre></td>
824<td class="lntd">
825<pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="c">&lt;!-- 比上面的配置好些 --&gt;</span>
826</span></span><span class="line"><span class="cl"><span class="nt">&lt;match</span> <span class="na">target=</span><span class="s">&#34;pattern&#34;</span><span class="nt">&gt;</span>
827</span></span><span class="line"><span class="cl">  <span class="nt">&lt;test</span> <span class="na">name=</span><span class="s">&#34;lang&#34;</span> <span class="na">compare=</span><span class="s">&#34;contains&#34;</span><span class="nt">&gt;</span>
828</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>en<span class="nt">&lt;/string&gt;</span>
829</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/test&gt;</span>
830</span></span><span class="line"><span class="cl">  <span class="nt">&lt;test</span> <span class="na">name=</span><span class="s">&#34;family&#34;</span> <span class="na">compare=</span><span class="s">&#34;contains&#34;</span><span class="nt">&gt;</span>
831</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Noto Sans CJK<span class="nt">&lt;/string&gt;</span>
832</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/test&gt;</span>
833</span></span><span class="line"><span class="cl">  <span class="nt">&lt;edit</span> <span class="na">name=</span><span class="s">&#34;family&#34;</span> <span class="na">mode=</span><span class="s">&#34;prepend&#34;</span> <span class="na">binding=</span><span class="s">&#34;strong&#34;</span><span class="nt">&gt;</span>
834</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Noto Sans<span class="nt">&lt;/string&gt;</span>
835</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/edit&gt;</span>
836</span></span><span class="line"><span class="cl"><span class="nt">&lt;/match&gt;</span>
837</span></span></code></pre></td></tr></table>
838</div>
839</div><p>让西文字体替换规则只在 en 环境中有效,在无语言或者其他语言的
840情况下,继续使用中文字体中的西文字形和全角引号。</p>
841<p>我现在想在等宽字体中优先使用 Iosevka Term,所以可以这样写:</p>
842<div class="highlight"><div class="chroma">
843<table class="lntable"><tr><td class="lntd">
844<pre tabindex="0" class="chroma"><code><span class="lnt">1
845</span><span class="lnt">2
846</span><span class="lnt">3
847</span><span class="lnt">4
848</span><span class="lnt">5
849</span><span class="lnt">6
850</span><span class="lnt">7
851</span><span class="lnt">8
852</span><span class="lnt">9
853</span></code></pre></td>
854<td class="lntd">
855<pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="nt">&lt;match</span> <span class="na">target=</span><span class="s">&#34;pattern&#34;</span><span class="nt">&gt;</span>
856</span></span><span class="line"><span class="cl">  <span class="nt">&lt;test</span> <span class="na">name=</span><span class="s">&#34;family&#34;</span> <span class="na">compare=</span><span class="s">&#34;contains&#34;</span><span class="nt">&gt;</span>
857</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Noto Sans Mono CJK<span class="nt">&lt;/string&gt;</span>
858</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/test&gt;</span>
859</span></span><span class="line"><span class="cl">  <span class="nt">&lt;edit</span> <span class="na">name=</span><span class="s">&#34;family&#34;</span> <span class="na">mode=</span><span class="s">&#34;prepend&#34;</span> <span class="na">binding=</span><span class="s">&#34;strong&#34;</span><span class="nt">&gt;</span>
860</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Iosevka Term<span class="nt">&lt;/string&gt;</span>
861</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/edit&gt;</span>
862</span></span><span class="line"><span class="cl"><span class="nt">&lt;/match&gt;</span>
863</span></span><span class="line"><span class="cl"><span class="c">&lt;!-- 糟糕!Chrome 的中文字体不是我想要的 --&gt;</span>
864</span></span></code></pre></td></tr></table>
865</div>
866</div><p><strong>注意!</strong> 有些程序居然只使用 font pattern 结果中的首个字体,
867比如 Chrome,虽然 Chrome 接受了我们指定的西文字体,但是它
868忽略了紧接其后的中文字体,即使配置采用了强绑定!然后中文字体
869又不知道它 fallback 到哪去了,可能会出现你想要的中文字体,
870也可能不是。所以,可以这样做:</p>
871<div class="highlight"><div class="chroma">
872<table class="lntable"><tr><td class="lntd">
873<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
874</span><span class="lnt"> 2
875</span><span class="lnt"> 3
876</span><span class="lnt"> 4
877</span><span class="lnt"> 5
878</span><span class="lnt"> 6
879</span><span class="lnt"> 7
880</span><span class="lnt"> 8
881</span><span class="lnt"> 9
882</span><span class="lnt">10
883</span><span class="lnt">11
884</span><span class="lnt">12
885</span></code></pre></td>
886<td class="lntd">
887<pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="c">&lt;!-- 比上面的配置好些 --&gt;</span>
888</span></span><span class="line"><span class="cl"><span class="nt">&lt;match</span> <span class="na">target=</span><span class="s">&#34;pattern&#34;</span><span class="nt">&gt;</span>
889</span></span><span class="line"><span class="cl">  <span class="nt">&lt;test</span> <span class="na">name=</span><span class="s">&#34;prgname&#34;</span> <span class="na">compare=</span><span class="s">&#34;not_eq&#34;</span><span class="nt">&gt;</span>
890</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>chrome<span class="nt">&lt;/string&gt;</span>
891</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/test&gt;</span>
892</span></span><span class="line"><span class="cl">  <span class="nt">&lt;test</span> <span class="na">name=</span><span class="s">&#34;family&#34;</span> <span class="na">compare=</span><span class="s">&#34;contains&#34;</span><span class="nt">&gt;</span>
893</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Noto Sans Mono CJK<span class="nt">&lt;/string&gt;</span>
894</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/test&gt;</span>
895</span></span><span class="line"><span class="cl">  <span class="nt">&lt;edit</span> <span class="na">name=</span><span class="s">&#34;family&#34;</span> <span class="na">mode=</span><span class="s">&#34;prepend&#34;</span> <span class="na">binding=</span><span class="s">&#34;strong&#34;</span><span class="nt">&gt;</span>
896</span></span><span class="line"><span class="cl">    <span class="nt">&lt;string&gt;</span>Iosevka Term<span class="nt">&lt;/string&gt;</span>
897</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/edit&gt;</span>
898</span></span><span class="line"><span class="cl"><span class="nt">&lt;/match&gt;</span>
899</span></span></code></pre></td></tr></table>
900</div>
901</div><p>在所有情况下,除了程序名为 Chrome 的情况下,
902优先使用 Iosevka Term 显示西文,
903再用 Noto Sans Mono CJK 显示中文。虽然我不能让 Chrome 使用 Iosevka Term,
904但它一定能用上 Noto Sans Mono CJK 显示中文。
905由于排除了 Chrome,所以无法解决 Chrome 中的全角引号问题。</p>
906<p>
906那么上面那些字体覆盖规则不都有这个问题吗?没关系,在一份语言标记为 en 的
907Web 页面中,出现中文的情况是罕见的,所以我不怎么担心 Chrome 使用了
908哪个中文字体。实际上,我平时用 Firefox 不用 Chrome,完全没这个烦恼。</p>
909<h2 id="不能解决的问题">不能解决的问题</h2>
910<p>虽然 fontconfig 本身不负责渲染字体,实际渲染是由程序交给 freetype 来完成的;
911但是 fontconfig 在处理 font pattern 的时候可以修改一些渲染参数,比如是否
912开启 hinting 和子像素渲染,是否开启连字特性。
913同时也可以根据实际情况来选择和过滤字体,比如根据像素尺寸分别
914指定字体,又或者控制何时使用点阵字体。
915所以渲染效果如何,不仅仅是 fontconfig 的问题,同时也是桌面程序自身以及
916freetype 的问题。你可以用 fontconfig 控制一些渲染特性和参数,指定
917渲染效果更好的字体,但不能指望 fontconfig 百分百帮你处理所有的渲染问题。</p>
918<p>Linux 不强迫程序必须使用特定的依赖,而是程序主动选择了约定俗成的依赖。
919老话重谈,程序可以自由选择完全遵守 fontconfig,也可以选择部分使用
920fontconfig 的配置,或者完全不遵守它。
921只不过现如今大部分 Linux 程序都能很好地和 fontconfig 协同工作,
922因为绝大部分 Linux 程序使用了 Qt 或者 GTK 这些部件库来开发界面,
923而 Qt 和 GTK 本身就依赖 fontconfig,它们参与其中,
924从而让程序默认就遵守了 fontconfig 的配置。
925如果程序不采用 Qt 和 GTK 来开发界面,而是自己来绘制窗口,
926那么也会尽可能地使用 fontconfig,这在一些朴素的虚拟终端模拟器上
927得到了体现,比如虚拟终端 Alacritty 在没有使用 Qt 或者 GTK 开发界面的情况下,
928直接调用 fontconfig 和 freetype 来渲染字体。</p>
929<p>只能说现如今的 Linux 程序的行为如此,但也有少部分程序
930使用 Xft,那么就不是 fontconfig 能管得了的。这体现在一些历史悠久的软件上,
931比如虚拟终端 rxvt,以及一些古朴的游戏。它们是从 Xft 的配置中,读取
932字体配置的。</p>
933<p>也有些程序可以使用自己打包的运行时环境,它自身携带的 fontconfig 库和配置
934与系统端的 fontconfig 相互独立。
935比如 Steam, 它的第一个启动框还遵守着我们系统上的 fontconfig 配置和字体文件,
936因为这个启动框是 Steam 通过使用 zenity 绘制的。
937在 Steam 进入主界面后,Steam 会使用自己运行时环境中的 fontconfig,并且使用
938自己的字体文件。所以我们的 fontconfig 配置对 Steam 无效。</p></article>
939
940    
941    
942    
943    
944    <section class="article license-custom"><a rel="license" href=https://creativecommons.org/licenses/by-nc-sa/4.0/ target="_blank">
945      <img alt="CC BY-NC-SA 4.0" width=80 height=15
946        src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAAPCAIAAAD8q9/YAAAABGdBTUEAANbY1E9YMgAAAapJREFUSMflljFPAjEUx98HsMUb2aBqdCKSToQ4cHTD9SYSx2Nw0sFOJMQB2DCBpV/hnNTFwOAEIaTxG/AV&#43;hVqtOQ8oXdybue93HBp3mvv9/7vvStADk3nxr6BH5&#43;C6NO57gDAcDi0hjHGMMYTMTbOq/dV4bCQCV3twBMxxhjH0YbMp2enxn/6Nu31ehkGrl/Uy&#43;Vycm1IKQGgfdU2IUu5bF22sgqMMDLySikJIQDAGFNKMcYAgBAipTQiV2k1rOrRw8g6F7YP&#43;/luXYxGWZ0TTknwtwN377sAMJvNtNaEEM/ztNb8yxzHUUoJIYIgMIsIo7Cq54u5dfetl7gP2s2ONVlxOUrnHwW&#43;vbsBACmlUio6tzzPo5RGq5pzjjE2US&#43;vz4vVIiH3VhnjIONSs7vnrrwJIqdQmDHm&#43;75RmHMuhNgojFIonJB7axn/qthW7B8V/uxhtOnhIAgcxwEA3/fDHqaUrtdrrXWz2aycV/bs4f2B9&#43;/huDGRGrhWr5VKpRxN6YkYI3QwGAwSgF3XPT45&#43;if/4XB09ft9K23DbRSLxWzftPJ1l86VfQA/Yr8BK4J&#43;aAAAAABJRU5ErkJggg==" />
947    </a>
948    <p>© 2020-2024 rydesun</p>
949  </section></div>
950
951  
952  
953    <div id="article-sidebar" class="article sidebar">
954      <button onclick="sidebarManager.toggle()">目录</button>
955      <nav id="TableOfContents">
956  <ol>
957    <li><a href="#混乱的现状">混乱的现状</a>
958      <ol>
959        <li><a href="#配置路径">配置路径</a></li>
960        <li><a href="#关于合成字体">关于合成字体</a></li>
961        <li><a href="#关于网页">关于网页</a></li>
962      </ol>
963    </li>
964    <li><a href="#解决问题">解决问题</a>
965      <ol>
966        <li><a href="#全角引号">全角引号</a></li>
967        <li><a href="#异体字">异体字</a></li>
968        <li><a href="#中文字体的西文部分">中文字体的西文部分</a></li>
969      </ol>
970    </li>
971    <li><a href="#字体比较与选择">字体比较与选择</a>
972      <ol>
973        <li><a href="#编程字体">编程字体</a></li>
974        <li><a href="#思源字体">思源字体</a></li>
975        <li><a href="#更纱黑体">更纱黑体</a></li>
976        <li><a href="#我的选择">我的选择</a></li>
977      </ol>
978    </li>
979    <li><a href="#基本思路">基本思路</a></li>
980    <li><a href="#第一步设置默认字体">第一步:设置默认字体</a></li>
981    <li><a href="#第二步按语言选择异体字">第二步:按语言选择异体字</a></li>
982    <li><a href="#第三步替换任意字体">第三步:替换任意字体</a></li>
983    <li><a href="#第四步覆盖西文字体">第四步:覆盖西文字体</a></li>
984    <li><a href="#不能解决的问题">不能解决的问题</a></li>
985  </ol>
986</nav>
987    </div>
988  
989</main>
990
991<div class="article bottom">
992  
993  <section id="discussion-area" class="article discussion">
994  <div id="remark42"></div>
995</section></div></section><section id="footer"><div class="footer-wrap">
996  <p class="copyright">© 2020-2024 rydesun</p>
997  <p class="powerby">
998    <span>Powered by</span>
999    <a href="https://gohugo.io" target="_blank" rel="noopener">Hugo</a>
1000    <span>&</span>
1001    <a href="https://github.com/cntrump/hugo-notepadium" target="_blank"
1002      rel="noopener">Notepadium</a>
1003    <span>(<a href="https://github.com/rydesun/catcat.cc" target="_blank"
1004      rel="noopener">modified</a>)</span>
1005  </p>
1006</div>
1007</section></body>
1008
1009</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.