奇怪的媒介

翻出一篇非常老的博客文章 http://www.456bereastreet.com/archive/200408/sizing_monospaced_fonts/,其中提出了一个问题:“使用等宽字体族时,字体大小为什么会有差异?” 像往常一样,对于 Web 浏览器来说,这个答案非常有趣(用浏览器开发者的话来说,就是“令人难以置信地困惑”)。

Web 浏览器中显示的默认字体大小是逻辑的,即 CSS 关键字 medium。有些浏览器在怪异模式(quirks mode)下使用其他逻辑大小关键字作为默认字体大小(本质上是一个单位的差异),但其思想仍然是一样的:没有指定绝对字体大小。相反,字体大小由浏览器引擎根据用户设置决定。像 medium 这样的逻辑关键字的问题在于它们不只映射到一个单一的用户定义值。

尝试打开 Safari 偏好设置,前往“外观”面板。你会看到可以为比例字体和等宽字体填写信息。所有比例字体的典型默认字体大小是 16px,所有等宽字体是 13px。这是我们在深入探讨时需要记住的关键概念:根据字体族类型指定独特默认字体大小的能力,会导致 CSS 字体大小关键字的实际含义产生歧义。

这里有一个简单的例子

<div style=”font-size:medium”>没有等宽字体的 Hello world。<tt>有等宽字体的 Hello world</tt></div>

假设你没有更改默认设置,你在上面的例子中应该看到一个 16px 的比例字体“没有等宽字体的 Hello world”消息,后面跟着一个只有 13px 高的等宽字体“有等宽字体的 Hello world”消息!大小不同,这是怎么回事?CSS 不是说字体大小应该被继承吗?

为了尊重用户对等宽字体的偏好设置,浏览器会尝试调整大小以适应等宽字体偏好。实际上,继承的不是 16px 的值,而是一个逻辑大小 medium,其值会根据是否使用了通用字体族而变化。

这种奇怪继承最基本的例子是 <pre> 和 <tt>,它们都被定义为具有font-family: monospace在现代浏览器的用户代理样式表(user agent style sheets)中。因此,在没有明确指定大小的情况下,浏览器必须进行调整以尊重用户设置。这些基本例子是可互操作的(interoperable)。

换句话说,你可以将之前的例子改写如下,得到相同的结果

<div style=”font-size:medium”>没有等宽字体的 Hello world。<span style=”font-family: monospace”>有等宽字体的 Hello world</span></div>

由于浏览器何时应进行这种大小调整的规则未被指定,这取决于各自的引擎来决定何时以及如何进行这些调整。上面博客文章中引用的“错误”源于 WebKit 在其他浏览器决定不进行调整的情况下,决定进行这种大小调整。

该错误中的具体示例基本上可以归结为这一点

<div style=”font-size:medium”>没有等宽字体的 Hello world。<span style=”font-family: Courier, monospace”>有等宽字体的 Hello world</span></div>

这个例子与上一个几乎相同。唯一的区别是在使用 monospace 通用字体族之前指定了一个命名字体。WebKit 查看该 font-family 声明,并(正确地)假定所使用的字体是等宽字体。因此,引擎会调整 medium 的逻辑值,以匹配用户的等宽字体大小偏好。在这种特定情况下,其他浏览器不会进行调整。

考虑这个例子

<div style=”font-size:medium”>没有等宽字体的 Hello world。<tt style="font-size: larger">有等宽字体的 Hello world</tt></div>

这里我们有一个 medium 比例字体和一个被指定为“larger”的等宽字体。现在如何确定正确大小的问题取决于浏览器引擎是决定“larger”意味着“取 16px 然后使其变大”还是“取 medium 然后使其变大”。事实证明,这个例子具有相当好的互操作性,Opera、Firefox 和 Safari 都选择了后者的定义。因此,等宽字体最终与它继承自的比例字体大小大致相同。

当然,这种调整并非只发生在一个方向上。考虑反向示例。

<tt style="font-size:medium">有等宽字体的 Hello world。<span style="font-size: larger">没有等宽字体的 Hello world</span></tt>

然而,还有更多有趣的例子,并且随着何时应用调整的歧义暴露出来,互操作性开始受到影响。这里就有一个这样的歧义

<tt style="font-size:medium">有等宽字体的 Hello world。<span style="font-family: Times">没有等宽字体的 Hello world</tt></span>

当明确指定了字体(font face),但未指定通用字体族时,该怎么办?在 Safari 2、Firefox 1.5 和 Opera 9 中,不会进行调整,因此比例字体不会变大。在 WebKit nightly 版本中,我们径直假定没有指定通用字体族的 font-family 应使用比例字体大小设置,因此我们进行了调整。

否则你可能会遇到这样的例子,其中进行调整显然是错误的,然而 Safari 2、Opera 9 和 Firefox 1.5 都这样做了。

<tt style="font-family: Verdana; font-size:medium">没有等宽字体的 Hello world。</tt>

当然,也可以提出反驳论点,认为应检查字体族列表中的实际字体,以决定整个字体族列表是等宽还是比例的,但在执行层叠(cascade)时这样做是成问题的。这就是为什么 WebKit 在 nightly 版本中现在只使用列表中的第一个通用字体族作为指导,如果不存在通用字体族,它会保守地假定为比例字体。

这个故事的寓意是:警惕tt, prefont-family: monospace.