点评一下合成字体,以及我的 Linux 桌面下主要应用的字体设置
font settings in my Linux Desktop Environment and current CJK-composite fonts
zping
1711 字
2025-07-30 20:14 +0000
虽然更纱黑体已经流行很久了,但是我一直都没有深入了解过。这两天因为想简化一下 Emacs 的配置,特意花时间研究了一下比较流行的两个合成字体枫叶等宽(Maple Mono)和更纱黑体(Sarasa-Gothic)。
合成字体其实就是把几个字体拼在一起。如果配置过 Emacs 的中英文等宽混排,就会知道,要实现正确显示带多种语言文字的 ascii ,最好是中英文同时使用一款字体,往往需要找到一个刚刚好的字号。我自己其实长期使用 Noto Sans Mono CJK SC-12 的配置。在 Emacs 中,我们可以为不同的 face 指定不同的字体,像类似 markdown 文档中的表格,就是 (set-face-font 'markdown-table-face "Noto Sans Mono CJK SC-12") 。这样的配置会非常多,而引入合成字体直接做一个全局配置就能解决大部分需求,大大简化了字体的配置。
最后试用下来,第一点,字符集的覆盖程度。对希腊和西里尔字母的覆盖对于我来说还是比较重要的,两款都有做这两个字符集的覆盖,更纱是的字体是专门配套的,而枫叶上游的 JetBrains Mono 也是有这个支持的。对于一些冷门符号,像易经或者盲文这些,基本上都是更纱覆盖得更全一些,但这种覆盖有点永无止境的意思,必然会有一些地方没有覆盖到。像中国象棋的一些符号。枫叶的版本只要做下去,未来肯定也会覆盖到。
按枫叶的作者介绍,枫叶本身被创造出来,是其觉得更纱的英文字体,相对于普通英文字符过窄。老实说如果不是他指出这个问题,我根本不会察觉。但枫叶为了追求英文字体的效显效果,让中文字符间距过宽这一点,我倒是一测试马上就发现了。可能也是因为我自己视力不佳,因此会特意把各种字体往大了配置。字符间距过宽这一点更容易被注意到。我之前一直有强调,只要你的屏幕足够大或者足够多,很多字体上显示问题就不是问题。
对于枫叶而言,虽然它强调自己保证英文的显示效果,但它的英文部分使用的是 JetBrains Mono ,而这款字体,也像其它编程字体一样,有合字设计(ligature),这个高级功能按理说应该是一个优点。只是这个字体,作为一款编程字体,竟然把两个等号也连在了一起,这样我这个乡下人就无法接接受这种高级功能了。这里要提一下,而更纱在这方面的处理没有那么激进。当然这一点对于 Emacs 来说并不是问题,因为 Emacs 的合字默认并不开启,需要安装专门的 el 包,哪怕开启,也可指定对哪些字符开启。但是对于像 ghostty 这样的现代作品,这个就是一个问题。
更纱的英文是专门设计的,而且根据场景的不同都有一些优化,虽然跟我自己比较习惯的 Source Code Pro 还有差距,但确实对我个人是可以接受的。当然,我在拉丁、希腊、西里尔字符集方向的风格偏好,其实是 Source Code Pro 这种,其与思源中日韩在风格上要一致得多。
这里还有一点要提一下,上一篇我提到过引号的问题,这次就特别注意了上面提到的两款字体的处理。对于单双引号是和英文字符一样的宽度,而不是中文。这个处理,如果只是日常显示的话,确实无伤大雅,但并不是规范的中文字体处理。这也是混排时没有办法,要迁就英文显示必然做的处理。
写到这里我就突然发现 Emacs 在配置方面的灵活性确实确实难以超越。自己之前的凑合出来的方案,现在还没有过时。当然,这些字体也不是完全无用的,对于一些配置手段比较单一的应用,比如像 ghostty 这样的虚拟终端来说,把首选字体换成 Sarasa Term Slab SC 还是有意义的,至少可以兼顾混排 ascii 表格的的显示,当文件名中包含文名时,看着也顺眼一些。而对于浏览器这类应用,也是一样,一款覆盖的字符集较多的合成字体也确实可以提升使用时的观感。
还有两个知识点, Slab 这个变体指的是一种特殊的衬线(Serif)字体,在更纱的说明文档中被翻译为“粗衬线体”。这种字体单个字母的装饰要相对夸张,但过多的装饰有时反而会造成辨识上的问题。不过正如我说的,只要实际的字符,足够大很多问题都不是问题。
另一点则是大部分字体显示符号类字符时多数需要至少两个拉丁字母的宽度,但 Emacs 在计算显示字符宽度时,非常保守,像 (char-width ?★) 就是返回一。这在编辑带有这类符号的文本表格时也是不可能接受的。需要手动介入。
最后贴一下,我自己经过试用,总结出来的一个在易用性、字符集覆盖和显示效果上相对平衡的配置。
;; the main font
(set-frame-font "Sarasa Mono SC:pixelsize=20")
(dolist (range '((#xE000 . #xF8FF) ; BMP PUA
(#xF0000 . #xFFFFF) ; Plane 15
(#x100000 . #x10FFFF) ; Plane 16
))
(dolist (font '("Font Awesome 6 Brands" "Font Awesome 6 Free"))
(set-fontset-font "fontset-default" range font nil 'prepend)))
(dolist (script '(symbol chess-symbol))
(dolist (font '("Symbols Nerd Font Mono"
"Noto Color Emoji"
"Noto Sans Symbols 2"
))
(set-fontset-font "fontset-default" script font nil 'append)))
; make sure some characters display correctly in markdown or org tables
(dolist (range '((#xE000 . #xF8FF) ; BMP PUA
(#x2600 . #x26FF) ; Miscellaneous Symbols(CJK)
))
(set-char-table-range char-width-table range 2))