Content-Type: text/html; charset=
信息,这一般有最高的优先级;meta
header 中的 Content-Type 信息的 charset
部分,对于 HTTP 头未指定编码或者本地文件,一般是这么判断;日本语
这样的标记,使得日文汉字可以使用日文字体显示 (因为 Han Unification 导致这些汉字和中文里的汉字使用同样的代码点,尽管很多写法不同),"lang"
属性也可以在 HTTP 头、
或者
出现,用于标记整个文档的全局语言,通常这是一种好的习惯,方便浏览器进行字体匹配。
为了统一处理所有这些复杂的情况,我们要将文本分为由不同语言组成的小段,在有的文本布局引擎里,这个步骤称为“itemize”,分解后的文本段常被称作“text run”,但是具体划分的规则可能根据不同的引擎有所区别,比如 HarfBuzz 和 ICU 一般是根据要使用的不同排版类来划分 (常称作“shaper”),比如英语和法语可能使用同一个 shaper 排版,那么相邻的英语和法语文本就会划分到同一个 run 里,而希伯来文需要另一个 shaper,就划分到它自己的 run 里,以 HarfBuzz 为例,它有这样一些 shaper:
不少浏览器还会在这个划分下面,在确定具体使用的字体之后,根据使用字体的不同划分更细的 run,这种 run 可能称作“SimpleTextRun”,每个都会使用和相邻不同的字体,最后把它们逐一交给 shaper 进行排版得到要绘制的字形,这样一来,shaper 的工作就被简化为在确定的语言、确定的字体下排版确定的文本,生成对应的字形和它们应该放置的位置、占用的空间。下面先详细说说确定字体的步骤。
font
和 font-family
等规则。比如这样的规则:
p { font-family: Helvetica, Arial, sans-serif; } strong { font-weight: bold; }如果对于这样一段文本:
表示这个段落里优先使用 Helvetica 这个 family 的字体,如果找不到,就找 Arial,如果还是找不到,就用浏览器设置的默认非衬线字体 (有的浏览器,比如 Safari 只给你一个设置,有的像 Firefox 则允许根据不同语言设置,这时可以根据前面分析得到的文本 run 语言信息来判断该用哪个),这个过程非常简单,大家都很好理解。稍微复杂一点的是“jumps”,它应该继承父元素的A quick brown fox jumps over the lazy dog.
font-family
,也用 Helvetica,但不用默认的 Regular,而用 Bold 版本,假如找不到 Helvetica Bold,就找 Arial Bold,否则就找浏览器设置的那个字体的 Bold 版本,假如都没有呢?就要考虑用人工伪造的方式来显示粗体了,这个且按下不谈,先看对于中文常见的情况:CSS 指定的字体没有覆盖我们需要的文本时,该怎么做。比如还是上面的 CSS 规则,但对这样的文本:
这里的“一只敏捷的狐狸”该用什么字体呢?假设 CSS 里具体指定了中文字体,比如一只敏捷的狐狸...
Helvetica, STHeiti, sans-serif
,那很简单,按照英文字体一样的规则来判断:逐个字符尝试当前的字体是否提供了针对该字符的字形,如果没有则尝试下一个,要是到了最后都没找到匹配的字体呢?CSS 规范里只简单的说执行“system font fallback”,但这个过程在不同的浏览器下可能很不一样,比如 WebKit 会使用 font-family
列表里的第一个字体和这段文本所属的语言来寻找 fallback 字体,像 Times 这样的 serif 字体对应的中文 fallback 字体,在 Mac OS X 下是华文宋体 (STSong);而 Firefox 则会根据 sans-serif
这样的通用 font family 和对应的语言匹配到设置中针对对应语言的默认字体,比如在 Mac OS X 默认的中文非衬线字体是华文黑体 (STHeiti)。Linux 下一般通过 fontconfig 去根据语言、风格等参数来选择 fallback,但不同浏览器的实现还可能有区别;Windows 下则一般会使用系统的 Font Linking 机制,根据注册表内的 FontSubstitutes 信息来寻找。因为在这里不同的浏览器可能有不同的行为,所以建议在 CSS 中写明对应平台该用的字体。
具体的字体选择还有一些不太容易注意的细节,也是各个浏览器差异比较大的一点,可能会出现这样一些问题:
STXihei
,或者是否能用 full name 选择:有的浏览器不能正确地将 CSS 里对字体的 font-weight
或者 font-style
等要求映射到特定的字体上,尤其是在字体使用了非标准的 style 命名的情况下,考虑到很多厂商有自己的字体命名规则,这其实很容易出现,像 Helvetica Neue 的 UltraLight, Light, Regular, Medium, Bold 这些不同的 weight,是怎么对应到 CSS font-weight
的 100 到 900 数值上的?这就是特别容易出现 bug 的地方。"宋体"
来代表 "SimSun"
。以 Mac OS X 下的浏览器为例,Firefox 支持这样的写法,但基于 WebKit 的浏览器一般不支持,这样的问题 CSS 规范没有限定,所以无论哪种情况都是允许的。@font-face
规则则是对于现有规则的扩展,提供了 web fonts 功能,但字体匹配算法的逻辑并没有改变,详细的算法可以看 CSS 规范里的说明。
Helvetica, Arial
就比 Arial, Helvetica
或者只有 Arial
更好;STXihei, SimSun
这样的写法比较常见,如果写作 SimSun, STXihei
,但 Mac OS X 上装了 SimSun 效果就不会太好看。sans-serif
或者 serif
。"American Typewritter"
和 "Myriad Pro"
。
,可以使用的语言标记参见 W3C 的说明。