关于 Font 的疑问解答和新特性解析

May 08, 2020

前言

以前从没去系统了解过网页字体,但它却时时刻刻在影响用户的体验,作为前端的一部分,其重要性不言而喻,在此,记录我对字体的一些疑问和新特性解析。

Serif vs Sans Serif vs Monospace

翻译为中文依次为:衬线字体、无衬线字体、等宽字体,但它并不指代某一具体的字体,而是一种字体特征的字体合集。

衬线字体(Serif),意思是在字的笔画开始、结束的地方有额外的装饰,而且笔画的粗细会有所不同。

中文字体中的宋体就是一种最标准的衬线字体(从严禁角度来讲,只有西文字体有 serif 和 sans-serif 之分,中文字体有宋体、黑体、楷体、仿宋等风格之分)。

其实,我的博客标题就是使用了衬线字体(Merriweather)。

无衬线字体(Sans-serif)专指西文中没有衬线的字体,与汉字字体中的黑体相对应。与衬线字体相反,该类字体通常是机械的和统一线条的,它们往往拥有相同的曲率,笔直的线条,锐利的转角。

在我的博客正文中,使用的西文(除了代码段)都是 Montserrat 字体,他就是一种标准的无衬线字体。

等宽字体(Monospace)是指字符宽度相同的字体,常见于代码片段中: <code> </code> <pre> </pre> HTML 标记中,通常都是使用等宽字体。

而我的博客中,所有的代码片段都是使用了 JetBrains Mono 字体,因此在阅读代码时,感到非常舒适。

为了更好得理解以上内容,我们尝试做些实践,首先你要知道浏览器的字体显示不仅仅取决于 CSS 中的 font-family ,还取决于浏览器自身的字体设置,以 Chrome 为例,在 设置-外观-自定义字体 中,你可以看到以下默认字体设置:

我们创建一个 HTML 文件,写入以下代码:

html
<p style="font-family: sans-serif;">你好,JavaScript</p>
<p style="font-family: serif;">你好,JavaScript</p>
<pre style="font-family: monospace">你好,JavaScript</pre>
<code>你好,JavaScript</code>
html
<p style="font-family: sans-serif;">你好,JavaScript</p>
<p style="font-family: serif;">你好,JavaScript</p>
<pre style="font-family: monospace">你好,JavaScript</pre>
<code>你好,JavaScript</code>

第一行 你好,JavaScript 这 13 个字符被渲染为 Sans-serif 的首选字体:Microsoft YaHei(微软雅黑,支持中文和西文)。

第二行 你好,JavaScript 这 13 个字符被渲染为 Serif 的首选字体:SimSun(宋体,支持中文和西文)。

第三行 你好, 这 3 个字符被默认渲染为标准字体: Microsoft YaHei,JavaScript 这 9 个字符被渲染为 Monospace 的首选字体:Corbel(只包含西文)。

第四行同第三行。

我们可以自定义浏览器默认字体设置,改成自己喜欢的,如下图所示:

再去看看之前的那几句话,不出意料,全都变成了我们指定的字体。

font-weight 设置无效

在设置字体的粗细程度时,我都会使用 font-weight 属性,在大部分情况下只用到了 bold(加粗) 或 lighter(更细),直到我知道了 font-weight 不仅可以设置为关键字,还能设置为 <number>(使用 100 的整倍数,一般为 100 <= number <= 900)。

举个例子,font-weight: 600,效果等同于 bold,但我发现 700,800,900 的效果都和 600 一模一样。

其实,这取决于我使用了什么字体,我的字体只提供了 300,400,600 这三种粗细(细体、常规、粗体)样式,分别对应 lighter,normal,bold,而所谓的 800,900 其实由于回退机制被降至 600。

  • 如果指定的权重值在 400 和 500 之间(包括 400 和 500):
    • 按升序查找指定值与 500 之间的可用权重;
    • 如果未找到匹配项,按降序查找小于指定值的可用权重;
    • 如果未找到匹配项,按升序查找大于 500 的可用权重。
  • 如果指定值小于 400,按降序查找小于指定值的可用权重。 如果未找到匹配项,按升序查找大于指定值的可用权重(先尽可能的小,再尽可能的大)。
  • 如果指定值大于 500,按升序查找大于指定值的可用权重。 如果未找到匹配项,按降序查找小于指定值的可用权重(先尽可能的大,再尽可能的小)。

以上策略意味着,如果一个字体只有 normal 和 bold 两种粗细值选择,指定粗细值为 100-500 时,实际渲染时将使用 normal,指定粗细值为 600-900 时,实际渲染时将使用 bold 。

查看 Google Fonts Montserrat,可以看到 Montserrat 字体支持 18 种样式,意味着它可以随意设置为 100,200,300,400,500,600,700,800,900,并有实际渲染效果。

使用 Firefox 的字体调试工具

开发者工具-检查元素 这一方面,我倒是觉得 Firefox 体验非常不错,远胜于 Chrome。

以字体为例,我在 Firefox 中打开 我的博客-关于,打开查看器,定位至中间那段自我介绍文字。

打开下方 字体面板,可以很直观得看到这段 <div></div> 所包裹的文字区域全部的字体信息。

我可以很方便调整字体的大小、行高、间距、字重或设置为斜体。

当我把鼠标悬浮在 Merriweather Black 文字上(右侧蓝色区域)时,浏览器会高亮应用了该字体的字符。

在感到有趣的同时,我也产生了疑惑:为什么会产生 Merriweather Black ,我明明只使用了 Merriweather 字体,它和 Merriweather 有什么联系吗?

我下意识去查看 CSS 文件中的 @font-face 定义,于是找到了答案。

css
/* merriweather-900normal - latin */
@font-face {
font-family: "Merriweather";
font-style: normal;
font-display: swap;
font-weight: 900;
src: local("Merriweather Black"), local("Merriweather-Black"),
url("./files/merriweather-latin-900.woff2") format("woff2"), /* Super Modern Browsers */
url("./files/merriweather-latin-900.woff") format("woff"); /* Modern Browsers */
}
css
/* merriweather-900normal - latin */
@font-face {
font-family: "Merriweather";
font-style: normal;
font-display: swap;
font-weight: 900;
src: local("Merriweather Black"), local("Merriweather-Black"),
url("./files/merriweather-latin-900.woff2") format("woff2"), /* Super Modern Browsers */
url("./files/merriweather-latin-900.woff") format("woff"); /* Modern Browsers */
}

font-family: "Merriweather" 是我自定义的字体名称,它代表一个系列,我可以改成 font-family: "A" 或者 font-family: "B",单纯起到辨识作用。

Merriweather Black 才是真正使用的字体名称,它在 src 中被定义。

结合 font-weight 的知识,可以得出 Merriweather 是一个字体系列,它包含了不同样式,其中的每个样式均指向一个不同的字体资源集。每个 src 描述符则又包含一个用逗号分隔的资源变体优先级列表:

  • local() 指令用于引用、加载和使用安装在本地的字体。

  • url() 指令用于加载外部字体,它可以包含可选的 format() 提示,指示由提供的网址引用的字体格式。

bash
├── merriweather-latin-300.woff
├── merriweather-latin-300.woff2
├── merriweather-latin-300italic.woff
├── merriweather-latin-300italic.woff2
├── merriweather-latin-400.woff
...
bash
├── merriweather-latin-300.woff
├── merriweather-latin-300.woff2
├── merriweather-latin-300italic.woff
├── merriweather-latin-300italic.woff2
├── merriweather-latin-400.woff
...

而 Merriweather Black 相当于 900 的别名,它是由字体内部决定的,具体参照 Merriweather Styles

font-display: swap 表示 Merriweather 等此类自定义的 Web Font 还未加载完毕时,先使用系统默认字体,待 Web Font 加载完毕后,再进行替换,可有效避免白屏。

font-style: normal 表示为 Merriweather 选择常规样式,它还可以设置为 italic | oblique,来设置斜体 | 倾斜体。甚至你可以设置为 font-style: oblique -30deg;,它可以精确控制 oblique 字体的倾斜程度。

注意:oblique <angle> 作为 CSS4 的工作草案,其兼容性不佳,经过实测 Firefox 可以,Chrome 不支持

可变字体(Variable font)

灵活(可变)字体 - Variable fonts 是 OpenType 字体方案的一个演进版本,它允许将多种不同的字体字型信息组合进一个单独的文件中,无需再为每一种不同字宽、字重或不同样式的字体分割为不同的字体文件。你只需通过 CSS 与一行@font-face 引用,即可获取包含在这个单一文件中的各种字体变体。本文将提供足够的信息以便你开始使用灵活字体(variable fonts)。

在这样的情景下,为了在一个单纯显示进行正文展示的页面中使用一个字体,你至少需要四个字体文件:常规、斜体、加粗、斜体加粗。如果你想添加更多的字重,比如让题注更轻或让额外强调的地方更重,意味着你需要更多文件。这就导致了更多大量 HTTP 请求的产生,同时也需要下载更多的数据(通常每个文件至少有 20k 或更多)。

你可以通过 v-fonts.com 来亲自体验可变字体是如何改变的。

在网页中,它是通过 font-variation-settings 属性进行控制,font-variation-settings CSS 属性提供了对 variable font 特征的低级控制,通过指定要更改的特征的四个字母轴名称及其值。

Axis Tag CSS Property 常见值
"wght" font-weight(字重) 1 - 1000 之间的任何数字都是有效的
"wdth" font-stretch(字宽) 任何大于 0 的数字在技术上都是有效的
"ital" font-style: italic(斜体) 0 或 1
"slnt" (slant) font-style: oblique + angle(倾斜) -90 - 90 度的任何值都是有效的
"opsz" font-optical-sizing(光学尺寸) 根据 font-size 自动应用

不同的可变字体,可用属性和值都不尽相同,这具体取决于字体是如何被设计的。

为了更好地理解可变字体,我们还是进入实践部分,首先确保你的系统上安装有 AmstelvarAlpha 字体。

创建 HTML 文件,用 Firefox 打开!用 Firefox 打开!用 Firefox 打开!

html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<style>
html {
font-family: "AmstelvarAlpha Default";
}
p {
font-size: 2em;
}
</style>
<body>
<p class="sample">
...it would not be wonderful to meet a Megalosaurus, forty feet long or
so, waddling like an elephantine lizard up Holborn Hill.
</p>
</body>
</html>
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<style>
html {
font-family: "AmstelvarAlpha Default";
}
p {
font-size: 2em;
}
</style>
<body>
<p class="sample">
...it would not be wonderful to meet a Megalosaurus, forty feet long or
so, waddling like an elephantine lizard up Holborn Hill.
</p>
</body>
</html>

打开字体面板,出现了更多的字体配置项,你可以拖动来体验可变字体带来的直观感受。

font-feature-settings

font-feature-settings 属性用于控制 OpenType 字体中的高级印刷功能。该属性是一个比较偏底层的功能接口,用于解决由于没有其他方法去访问和设置 OpenType 字体某些特性而无法解决一些特殊功能需求。

我的理解是它可针对 OpenType 字体做一些个性化设置,不同的字体能设置的 feature 属性不尽相同。这块内容过多,具体参照 The Complete CSS Demo for OpenType Features

我以 Warnock Pro 字体为例,实现以下 features:

  • 用老式数字替换默认数字
css
.of-onum {
font-feature-settings: "onum";
}
css
.of-onum {
font-feature-settings: "onum";
}

  • 用下标字形替换默认字形
css
.of-sinf {
font-feature-settings: "sinf";
}
css
.of-sinf {
font-feature-settings: "sinf";
}

  • 用划线 0 替代 正常 0
css
.of-zero {
font-feature-settings: "zero";
}
css
.of-zero {
font-feature-settings: "zero";
}


B2D1 (包邦东)

Written by B2D1 (包邦东)