字体可以有效地影响整个界面的氛围, 给人以“设计感”。 如果你经常阅读 / 修改代码, 不妨为代码挑选一款合适的字体。
考虑到现代的系统与软件往往会提供足够好的默认字体设置, 不用用户再折腾。 再加上既有的习惯并不容易改掉, 所以本文的知识没什么用1。 而且这绝不是在自嘲。
TL;DR - 我自己在用的字体是 Go Mono。
等宽字体 vs. 比例字体
按照绝大多数软件的默认设置, 代码要用等宽字体来展示。 等宽字体可以做到在垂直方向上按照列数对齐。 因为,呃,每个字符宽度相等。 让空白符有语义的代码(例如 Python,YAML)可能必须要有这样的对齐, 才会比较易读。
再者, 有些代码风格会希望让跨越多行的同类语法结构在垂直方向上对齐。 如果你需要看图演示, vim-easy-align 这个 Vim 插件的 README 里面用 gif 图片演示了多个例子。 我自己倒是对这种风格没什么兴趣。
垂直对齐的另一个好处是可以在字符界面绘图。 比如现代的编程工具(包括编译器,语法检查,测试框架等) 需要绘制这样的输出,来指出源码可能出错的位置:
error: expected type, found `}`
--> hello.rs:2:21
|
2 | println!("Yaye"): }
| ^
当然,等宽字体还可以用来画 ASCII art。
另有一个原因是,标点符号往往不是文字(特别是正文)的重点内容。 比例字体里的标点符号的尺寸往往偏小。 而在编程语言里,标点符号都在语法结构中起着重要作用, 现代的等宽字体就会为此设计易辨识(legible,而非 readable2)的符号。
不过话说回来,如果有某种专门为编程设计的比例字体, 能解决标点符号的易读性问题, 再放弃 ASCII art 等依赖垂直对齐的需求, 倒也不是不可以用来展示代码。 而且比例字体也有自己的优势,如:
- Kerning!
- 为每个字符分配更合适的空间。比如粗体,斜体,大写字母都需要更多的空间。 结合 Kerning 等功能,最终效果是视觉的美观。
- 连续多行的相同内容,如果其中某一行有 typo, 有可能因为宽度不同而容易被肉眼发现。
- 给定固定的行宽度,比例字体可以比等宽字体写更多的字符(平均来说)。
在 Reddit 上的这个讨论里面有很多信息。 可以肯定的是,这个世界上有人故意不用等宽字体写代码。
衬线体 vs. 非衬线体
当我因为开始学习 Web 前端开发而接触字体知识时, 首先了解到的知识就是衬线非衬线字体的区别。 衬线是否能改善字体的易辨识性, 传统的意见认为衬线体更易辨识, 只是这件事似乎并没有很可靠的理论基础 / 实验验证。
但是,在为代码设计的字体里,
很多字体没有严格遵守衬线 / 非衬线的限制,
而是为了把 ijlI1
这些字符分开,
故意把这些字符加上衬线,
而其余字符没有衬线(很可能是为了节省成本)。
这种 inconsistent 的设计出现在如下的流行字体:
- Apple 的 Menlo 和 SF Mono —— 这两个字体先后是 macOS 的新默认代码字体。 但我总觉得它们不如旧的 Monaco 更有个性。
- Google 的一系列字体: Droid Sans Mono,Roboto Mono, Cousine,Noto Sans Mono。
- Inconsolata
- Mozilla 的 Fira Mono
- Ubuntu Mono
上面提到的这些缺乏个性的字体我都不喜欢。除了 Monaco。
如果要求所有字符都加上衬线, 这倒是容易保持风格一致。 而且衬线等宽字体又非常地少见, 个性十足,极少撞……撞字?
字号
常见的字体格式 TTF 和 OTF 都是矢量字体, 可以按照用户指定的尺寸自由缩放。 不用太担心字体不支持显示器的分辨率的问题。
由于低分辨率下的反锯齿渲染往往会造成笔划边缘模糊, 有些字体为这种用例内嵌了位图(bitmap)版本。 甚至还有没有矢量的纯位图字体。 但位图字体的问题是:要为每种尺寸手动绘制, 制作成本太高。 通常只有在很小的字号上使用。
考虑到现在的显示器分辨率越发地高, 再加上视网膜屏这个产品概念的诞生, 让高端显示器的 DPI 更加地高, 上述的问题已经很少见, 位图字体也就很少纳入考量了。
字形比例
太胖或者太瘦的字体都不好看。 现代字体在设计长宽比时, 会考虑与经典字体的比例相接近 / 一致, 这样用新字体替换旧字体时, 更容易维持原有的排版设计。
Anonymous Pro 这个字体没能被我选中, 就是因为它和我以往惯用的等宽字体相比, 实在是偏胖。
一个特殊情况是, 如果用户愿意牺牲易辨识性来换取每行能显示更多的字符, 那么有可能会选择用细瘦的字体。 但是对于阅读代码这一用途而言, 牺牲易读性恐怕很难接受。
为编程设计的连字(Font Ligature)
这个玩意不知道是什么时候突然流行起来的。
简单来说,可以把 !=
渲染成 ≠
。
但这种连字符往往不是字体设计者会考虑到的,
而是由第三方 patch 进去的。
与原有字体的视觉风格不一定契合。
而且,如果你要修改代码,
例如说,把 !=
改成 ==
。
如果有 !
这个字符作为 anchor,
可以用搜索的方式快速把光标定位过去,
然后在 Vim 里按 r=
即可。
如果用了连字,
等于是把一个操作符原有的字符信息在视觉上隐藏了。
给编辑代码带来困难。
所以我在选择字体时, 不会考虑连字符这回事。 甚至于说,有它还不如没它。
结语
字体设计还有许多要素, 诸如,笔划粗细,支持的字符集等等。 这里不再多谈。
最终我在这里:http://programmingfonts.org/tagged/serif 找到了 Go Mono 字体: 所有字符都统一地有 Slab Serif, 宽度相对较窄,高宽比也合适。 虽然我还没有动力去学习 Go 语言, 但这个副产品让我很是满意。
延伸阅读
- Input Font 的设计考量:http://input.fontbureau.com/info/
- programmingfonts.org 收录了很多写代码用的字体
- 一些等宽字体渲染对比:https://app.programmingfonts.org/