对设计师和前端工程师来说,一个很熟悉的现象是,创建的文本框在实际文本上方和下方存在空隙,这意味着实际间距会比设定的间距值要大。

这套规则被使用了 24 年,直到现在,万维网联盟(W3C)决定引入新的 CSS 属性:leading-trim,能够将文本的上下空间修建掉,例如下面的例子,text-edge(也是一个新的属性)定义了文本边缘是字母高度和基线,leading-trim 将文本边缘外的空间去除。

h1 { 
 text-edge: cap alphabetic;
 leading-trim: both;
}

这个话题有趣的地方是文字上下方留有空间的历史原因,这可以追溯到 140 年前仍在使用的铅活字印刷,在行与行之间会插入细铅条,用来增加字行之间的垂直距离,这种细铅条被称为 leading(这里的 lead 不是指领导,而是铅的意思)。

而到了 1996 年推出的 CSS1,则将 leading 拆分成上下两部分(half-leading),其中一半 leading 属于上一行文字,另一半 leading 属于下一行文字,根据《深入探究 Figma 中的行高》里提到的,这种做法的原因是:

在印刷界和早期程序中,文字区块只需要将文字包裹在其中。Web 需要它做得更多。“我知道 half-leading 不是传统的印刷概念”,在 1995–1996 年负责 CSS1 的伯特·博斯(Bert Bos)说道:“但是如果仅仅在下方增加行距会导致使用背景或边框的时候出现问题。”

如果行距只出现在文字区块底部,会导致底部显得很重并需要额外工作才使效果好一点。Half-leading 提供了解决办法。

CSS 的另一个改变是什么?100% 的行高(line height)等于 100% 的字号(font size)。在此之前,字体设计师可能会给 16 像素字号的字体一个默认的 20 像素的行高。但是在 web,16-pixel 字号的字体的 100% 行高就是 16 像素,无论字体设计师当初如何定义。

这个策略的原因很简单:要知道一个字体的默认行高需要先加载这个字体,在早期的互联网会很慢。使行高等于字号则可以很快计算完成。“我们希望在没有加载字体的时候就尽可能多的进行计算”, CSS 联合作者哈科·尼姆·李(Håkon Wium Lie)提到。行高不再取决于内部的字体属性,好在字体不需要适应什么物理边界,所以这不算什么问题。

但这种做法也导致了新的问题,一种字体的不同字号都有一个默认行高(Default line height),且为了容纳一些字母(例如 g 的下半部分),默认行高往往比包含的文字要高,即会增加 half-leading 的大小,这就是我们目前现状的来源。

另一个可以延伸的话题是,编程语言是如何被制定出来的?(进一步的,我们什么时候需要一门新的编程语言?)和自然演变出的自然语言(natural language)不同,编程语言是一种形式语言(formal languages),是人类为了特殊用途而设计出来的。例如,数学家使用的记号(notation)就是形式语言,特别擅长表示数字和符号之间的关系。化学家使用形式语言表示分子的化学结构。 最重要的是:编程语言是被设计用于表达计算的形式语言。

自然语言和形式语言的区别有:

  • 歧义性:自然语言充满歧义,人们使用上下文线索以及其它信息处理这些歧义。形式语言被设计成几乎或者完全没有歧义,这意味着不管上下文是什么,任何语句都只有一个意义。
  • 冗余性:为了弥补歧义性并减少误解,自然语言使用很多冗余。结果,自然语言经常很冗长。形式语言则冗余较少,更简洁。
  • 字面性:自然语言充满成语和隐喻。如果我说“The penny dropped”,可能根本没有便士、也没什么东西掉下来(这个成语的意思是,经过一段时间的困惑后终于理解某事)。形式语言的含义,与它们字面的意思完全一致。

由于我们都是说着自然语言长大的,我们有时候很难适应形式语言。形式语言与自然语言之间的不同,类似诗歌与散文之间的差异,而且更加明显:

  • 诗歌:单词的含义和声音都有作用, 整首诗作为一个整理,会对人产生影响,或是引发情感上的共鸣。 歧义不但常见,而且经常是故意为之。
  • 散文:单词表面的含义更重要,句子结构背后的寓意更深。 散文比诗歌更适合分析,但仍然经常有歧义。
  • 程序:计算机程序的含义是无歧义、无引申义的, 通过分析程序的标记和结构,即可完全理解。

如果你对这一段内容感兴趣,可以阅读《Think Python》,这也是一本非常好的 Python 入门读物。