可变字体
可变字体是 OpenType 字体规范的一项演进,它允许将一种字体的多种变体整合到一个文件中,而无需为每个宽度、字重或样式都使用单独的字体文件。通过 CSS 和单个 @font-face 引用,就可以访问指定字体文件中包含的所有变体。本文将为你提供开始使用可变字体所需的所有知识。
备注:要在你的操作系统上使用可变字体,你需要确保它是最新的。例如,Linux 操作系统需要最新的 Linux FreeType 版本,而 macOS High Sierra (10.13) 之前的版本不支持可变字体。如果你的操作系统不是最新的,你将无法在网页或 Firefox 开发者工具中使用可变字体。
可变字体:它们是什么,以及有何不同
为了更好地理解可变字体的不同之处,有必要回顾一下非可变字体是什么样的,以及它们之间的比较。
标准(或静态)字体
过去,一种字体(typeface)会作为多个独立的字体文件(font)来制作,每个字体文件代表一种特定的宽度/字重/样式组合。因此,你会为“Roboto Regular”、“Roboto Bold”和“Roboto Bold Italic”分别准备不同的文件——这意味着你最终可能需要 20 或 30 个不同的字体文件来表示一个完整的字体(对于一个包含不同宽度的大型字体,这个数字可能会是好几倍)。
在这种情况下,要在网站上将一种字体用于正文的典型用途,你至少需要四个文件:常规体、斜体、粗体和粗斜体。如果你想添加更多的字重,比如为标题添加更细的字重或为特别强调的内容添加更粗的字重,那就意味着需要更多的文件。这会导致更多的 HTTP 请求和更多的数据下载(通常每个文件约 20k 或更多)。
可变字体
使用可变字体,所有这些排列组合都可以包含在一个文件中。这个文件会比单个字体文件大,但在大多数情况下,它比你可能为正文加载的 4 个文件要小或者大小相当。选择可变字体的优势在于,你可以访问所有可用的字重、宽度和样式范围,而不再受限于你之前需要单独加载的那几种。
这使得一些常见的排版技术成为可能,例如为不同大小的标题设置不同的字重以在各种尺寸下获得更好的可读性,或者为数据密集型的显示使用稍窄的宽度。作为比较,在杂志的排版系统中,通常会在整个出版物中使用 10-15 种甚至更多的不同字重和宽度组合——这提供的样式范围比目前在 Web 上典型的(或者说仅出于性能原因就可行的)要广泛得多。
关于字体族、字重和变体的说明
你可能注意到,我们一直在讨论为每个字重和样式(即粗体、斜体和粗斜体)使用特定的字体文件,而不是依赖浏览器来合成它们。原因是大多数字体对于较粗的字重和斜体都有非常具体的设计,这些设计通常包含完全不同的字符(例如,小写字母“a”和“g”在斜体中通常有很大不同)。为了最准确地反映字体设计,并避免不同浏览器之间以及它们如何合成不同样式时可能出现的差异,在使用非可变字体时,在需要的地方加载特定的字体文件会更准确。
你可能还会发现,一些可变字体被分成两个文件:一个用于直立体及其所有变体,另一个包含斜体变体。这样做有时是为了在不需要或不使用斜体的情况下减少总体文件大小。在所有情况下,仍然可以将它们链接到一个共同的 font-family 名称,这样你就可以使用相同的 font-family 和适当的 font-style 来调用它们。
引入“变化轴”
新的可变字体格式的核心是变化轴的概念,它描述了字体设计中特定方面的允许变化范围。因此,“字重轴”描述了字形可以有多细或多粗;“宽度轴”描述了它们可以有多窄或多宽;“斜体轴”描述了是否存在斜体字形,并且可以相应地开启或关闭,等等。请注意,一个轴可以是一个范围,也可以是一个二元选择。字重可能范围是 1–999,而斜体可能是 0 或 1(关闭或开启)。
根据规范的定义,有两种类型的轴:注册轴和自定义轴。
- 注册轴是那些最常遇到的轴,其常见程度足以让规范的作者们认为有必要将其标准化。目前已注册的五个轴是字重、宽度、倾斜、斜体和视觉尺寸。W3C 已经着手将它们映射到现有的 CSS 属性上,并且在一种情况下还引入了一个新的属性,你将在下面看到。
- 自定义轴是无限的:字体设计师可以定义和限定任何他们喜欢的轴,只需要给它一个四个字母的标签,以便在字体文件格式中识别它。你可以在 CSS 中使用这些四字母标签来指定该变化轴上的一个点,如下面的代码示例所示。
注册轴和现有的 CSS 属性
在本节中,我们将通过示例和相应的 CSS 来演示定义的五个注册轴。在可能的情况下,标准语法和底层语法都会包含在内。底层语法(font-variation-settings)是第一个为测试可变字体支持的早期实现而实现的机制,并且对于利用五个注册轴之外的新轴或自定义轴是必需的。然而,W3C 的意图是,当有其他属性可用时,不应使用此语法。因此,只要有可能,就应该使用适当的属性,只有在需要设置其他方式无法设置的值或轴时,才使用 font-variation-settings 的底层语法。
注意
-
使用
font-variation-settings时,需要注意轴名称是区分大小写的。注册轴名称必须是小写,而自定义轴必须是大写。例如cssfont-variation-settings: "wght" 375, "GRAD" 88;wght(字重)是一个注册轴,而GRAD(等级)是一个自定义轴。 -
如果你已经使用
font-variation-settings设置了值,并且想要更改其中一个值,你必须重新声明所有这些值(就像使用font-feature-settings设置 OpenType 字体特性时一样)。你可以通过使用 CSS 自定义属性(CSS 变量)来为单个值设置,然后修改单个自定义属性的值来解决这个限制。示例代码将在指南的末尾提供。
字重
字重(由 wght 标签表示)定义了字形笔画可以有多细或多粗(在典型排版术语中称为 light 或 heavy)的设计轴。很长一段时间以来,CSS 已经可以通过 font-weight 属性来指定这一点,该属性接受从 100 到 900(以 100 为增量)的数值,以及像 normal 或 bold 这样的关键字,这些关键字是其相应数值的别名(在这种情况下是 400 和 700)。在处理非可变或可变字体时,这些仍然适用,但对于可变字体,现在任何从 1 到 1000 的数字都是有效的。
应该注意的是,目前在 @font-face 声明中,没有办法将可变字体的变化轴上的特定点“映射”到关键字 bold(或任何其他关键字)。这通常可以相当容易地解决,但确实需要在编写 CSS 时多一个步骤。
font-weight: 375;
font-variation-settings: "wght" 375;
点击下方代码块中的“运行”来在 MDN Playground 中编辑示例。编辑 CSS 代码来体验 font-weight 的值。
/* weight range is 300 to 900 */
.p1 {
font-weight: 625;
}
/* weight range is 300 to 900 */
.p2 {
font-variation-settings: "wght" 625;
}
/* Adjust with slider & custom property */
.p3 {
font-variation-settings: "wght" var(--text-axis);
}
宽度
宽度(由 wdth 标签表示)定义了字形可以有多窄或多宽(在排版术语中称为 condensed 或 extended)的设计轴。这通常在 CSS 中使用 font-stretch 属性来设置,其值表示为高于或低于“正常”(100%)的百分比,技术上任何大于 0 的数字都是有效的——尽管范围更有可能接近 100% 标记,例如 75%-125%。如果提供的数值超出了字体中编码的范围,浏览器应该以允许的最接近的值来渲染字体。
备注:在使用 font-variation-settings 时不使用 % 符号。
font-stretch: 115%;
font-variation-settings: "wdth" 115;
点击下方代码块中的“运行”来在 MDN Playground 中编辑示例。编辑 CSS 代码来体验 font-width 的值。
/* width range is 55% to 100% */
.p1 {
font-stretch: 60%;
}
/* width range is an integer from 55 to 100 */
.p2 {
font-variation-settings: "wdth" 60;
}
/* Adjust with slider & custom property */
.p3 {
font-variation-settings: "wdth" var(--text-axis);
}
斜体
斜体(ital)轴可以在 [0-1] 范围内设置,其中 0 表示“非斜体”,0.5 表示“半斜体”,1 表示“完全斜体”。斜体设计通常包含与其直立体版本截然不同的字形,因此在从直立体到斜体的过渡中,通常会发生一些字形(或字符)替换。斜体(Italic)和伪斜体(oblique)通常被交替使用,但实际上它们有很大的不同。伪斜体在此上下文中用术语 slant(见下文)定义,一种字体通常只会有其中一种,而不会两者都有。
在 CSS 中,斜体和伪斜体都使用 font-style 属性应用于文本。另请注意引入了 font-synthesis: none;——这将防止浏览器意外地同时应用变化轴和合成的斜体。这也可以用来防止伪粗体。
font-style: italic;
font-variation-settings: "ital" 1;
font-synthesis: none;
点击下方代码块中的“运行”来在 MDN Playground 中编辑示例。编辑 CSS 代码来体验 font-italics。
/* font-style: italic, with and without font-synthesis */
.p1 {
font-style: italic;
}
.p1-no-synthesis {
font-style: italic;
font-synthesis: none;
}
/* italic range is 0 or 1 */
.p2 {
font-variation-settings: "ital" 1;
font-synthesis: none;
}
/* Adjust with slider & custom property */
.p3 {
font-synthesis: none;
font-variation-settings: "ital" var(--text-axis);
}
倾斜
倾斜(由 slnt 标签表示),或者通常被称为“伪斜体”(oblique)——与真正的斜体不同,它改变了字形的角度,但不会进行任何字符替换。它也是可变的,因为它以数值范围表示。这使得字体可以在倾斜轴上的任何位置变化。允许的范围是从 -90 到 90 度。
可以控制倾斜的两个属性是 font-style 和 font-variation-settings。以下两个属性声明是相同的
font-style: oblique 14deg; font-variation-settings: "slnt" -14;
优先使用 font-style 属性,而不是 font-variation-settings 属性。使用 font-variation-settings 属性时,不使用 deg 关键字。此外,对于 font-variation-settings 属性,正角度表示逆时针倾斜。
在下面的实时示例中,你可以调整倾斜度。
.font-style {
font-style: oblique 5deg;
}
.font-variation {
font-variation-settings: "slnt" -5;
}
.adjustable {
font-variation-settings: "slnt" var(--slant-angle);
}
视觉尺寸
这对于数字字体和 CSS 来说是新事物,但在设计和制作金属活字方面,这是一项有数百年历史的技术。视觉尺寸调整(Optical sizing)是指根据物理尺寸改变字形整体笔画粗细的做法。如果尺寸非常小(例如相当于 10 或 12px),字符的整体笔画会更粗,并且可能还有其他一些小的修改,以确保它在物理上更小的尺寸下能够重现并可读。相反,当使用更大的尺寸时(比如 48 或 60px),粗细笔画之间可能会有更大的变化,从而更符合原始意图地展示字体设计。
虽然这最初是为了补偿油墨和纸张的印刷过程(小尺寸下非常细的线条通常无法印刷出来,导致字形看起来不完整),但它在补偿屏幕质量和物理尺寸渲染时,同样适用于数字显示。
视觉尺寸值通常旨在根据 font-size 自动应用,但也可以使用底层的 font-variation-settings 语法来操纵。
为了在 CSS 中支持可变字体,创建了一个新属性 font-optical-sizing。当使用 font-optical-sizing 时,唯一允许的值是 auto 或 none——所以这个属性只允许开启或关闭视觉尺寸调整。然而,当使用 font-variation-settings: 'opsz' <num> 时,你可以提供一个数值。在大多数情况下,你会希望将 font-size(字体被渲染的物理尺寸)与 opsz 值(这是使用 auto 时视觉尺寸调整的预期应用方式)相匹配。提供指定特定值的选项是为了在需要覆盖默认值时——无论是出于易读性、美学还是其他原因——可以应用一个特定的值。
font-optical-sizing: auto;
font-variation-settings: "opsz" 36;
点击下方代码块中的“运行”来在 MDN Playground 中编辑示例。编辑 CSS 代码来体验视觉尺寸的值。
.p1 {
font-optical-sizing: none;
}
/* font-optical-sizing can be auto or none */
.p2 {
font-optical-sizing: auto;
}
/* optical range is from 8 to 144 */
.p3 {
font-variation-settings: "opsz" 64;
}
/* Adjust with slider & custom property */
.p4 {
font-variation-settings: "opsz" var(--text-axis);
}
自定义轴
自定义轴正如其名:它们可以是字体设计师想象的任何设计变化轴。可能会有一些变得相当普遍——甚至成为注册轴——但这只有时间才能证明。
等级
等级(Grade)可能会成为更常见的自定义轴之一,因为它在字体设计中有已知的历史。设计不同等级的字体的做法通常是为了应对预期的用途和印刷技术。“等级”这个术语指的是字体设计的相对粗细或密度,但与传统的“字重”不同之处在于,文本所占的物理空间不会改变,因此改变文本等级不会改变文本的整体布局或其周围的元素。这使得等级成为一个有用的变化轴,因为它可以被改变或动画化,而不会导致文本本身的回流。
font-variation-settings: "GRAD" 88;
点击下方代码块中的“运行”来在 MDN Playground 中编辑示例。编辑 CSS 代码来体验 font-grade 的值。
/* grade range is 88 to 150 */
.p1 {
font-size: 64px;
font-variation-settings: "GRAD" 88;
}
/* Adjust with slider & custom property */
.p2 {
font-size: 64px;
font-variation-settings: "GRAD" var(--text-axis);
}
使用可变字体:@font-face 的变化
加载可变字体的语法与任何其他网络字体非常相似,但有一些显著的区别,这些区别是通过对传统 @font-face 语法的升级提供的,现在在现代浏览器中可用。
基本语法是相同的,但可以指定字体技术,并且可以为像 font-weight 和 font-stretch 这样的描述符提供允许的范围,而不是根据加载的字体文件来命名。
标准直立体(Roman)字体的示例
@font-face {
font-family: "MyVariableFontName";
src: url("path/to/font/file/my-variable-font.woff2")
format("woff2-variations");
font-weight: 125 950;
font-stretch: 75% 125%;
font-style: normal;
}
在这种情况下,font-style: normal 声明表示当 font-family 设置为 MyVariableFontName 并且 font-style 设置为 normal 时,应使用此字体文件。作为替代方案,你可以使用 font-style: oblique 0deg 或 font-style: oblique 0deg 20deg 来表示字体具有正常的直立字形(由 0deg 表示)。
仅包含斜体而不包含直立字符的字体示例
@font-face {
font-family: "MyVariableFontName";
src: url("path/to/font/file/my-variable-font.woff2")
format("woff2-variations");
font-weight: 125 950;
font-stretch: 75% 125%;
font-style: italic;
}
在这种情况下,font-style: italic 声明表示当 font-family 设置为 MyVariableFontName 并且 font-style 设置为 italic 时,应使用此字体文件。作为替代方案,你可以使用 font-style: oblique 14deg 来表示字体具有斜体字形。
包含伪斜体(倾斜)轴的字体示例
@font-face {
font-family: "MyVariableFontName";
src: url("path/to/font/file/my-variable-font.woff2")
format("woff2-variations");
font-weight: 125 950;
font-stretch: 75% 125%;
font-style: oblique 0deg 12deg;
}
在这种情况下,oblique 0deg 12deg 值表示当样式规则中 font-family 属性为 MyVariableFontName 并且 font-style 属性为 oblique 且角度在 0 到 12 度之间(含)时,应使用此字体文件。
备注:并非所有浏览器都实现了字体格式的完整语法,因此请仔细测试。所有支持可变字体的浏览器,如果你将格式设置为仅文件格式,而不是 format-variations(即使用 woff2 而不是 woff2-variations),它们仍然会渲染字体,但如果可能的话,最好使用正确的语法。
备注:为 font-weight、font-stretch 和 font-style 提供值范围将防止浏览器在您使用适当的属性(即 font-weight 或 font-stretch)时尝试渲染超出该范围的轴,但不会阻止您通过 font-variation-settings 提供无效值,因此请谨慎使用。
处理旧版浏览器
可变字体的支持可以通过 CSS 特性查询(参见 @supports)来检查,因此可以在生产环境中使用可变字体,并将调用可变字体的 CSS 范围限定在一个特性查询块内。
h1 {
font-family: some-non-variable-font-family;
}
@supports (font-variation-settings: "wdth" 115) {
h1 {
font-family: some-variable-font-family;
}
}
示例页面
以下示例页面展示了两种不同的 CSS 结构方式。第一个示例尽可能使用标准属性。第二个示例使用 CSS 自定义属性为 font-variation-settings 字符串设置值,并展示了如何通过覆盖单个变量而不是重写整个字符串来更轻松地更新单个变量值。注意 h2 上的悬停效果,它只改变了等级轴的自定义属性值。点击下方代码块中的“运行”来在 MDN Playground 中编辑示例。
.container1 h1 {
font-optical-sizing: auto;
font-size: 5rem;
font-stretch: 85%;
font-weight: 450;
}
.container1 h2 {
font-optical-sizing: auto;
font-size: 2.25rem;
font-stretch: 90%;
font-weight: 575;
}
.container1 p {
font-optical-sizing: auto;
font-size: 1rem;
font-stretch: 100%;
font-weight: 375;
}
.demo2 {
--text-wght: 375;
--text-wdth: 100;
--text-opsz: 16;
--text-GRAD: 88;
}
.container2 > * {
font-size: 5rem;
font-variation-settings:
"wght" var(--text-wght),
"wdth" var(--text-wdth),
"opsz" var(--text-opsz),
"GRAD" var(--text-GRAD);
}
.container2 h1 {
--text-wght: 450;
--text-wdth: 85;
--text-opsz: 80;
font-size: 5rem;
}
.container2 h2 {
--text-wght: 575;
--text-wdth: 95;
--text-opsz: 36;
font-size: 2.25rem;
}
.container2 h2:hover {
--text-GRAD: 130;
}
.container2 p {
font-size: 1rem;
}
资源
- W3C CSS Fonts Module 4 规范(编辑草案)
- W3C GitHub 问题队列
- 微软 Open Type Variations 介绍
- 微软 OpenType Design-Variation Axis Tag 注册表
- Wakamai Fondue(一个通过拖放检查界面告诉你字体能做什么的网站)
- Axis Praxis(最初的可变字体游乐场网站)
- V-Fonts.com(一个可变字体目录及获取途径)
- Font Playground(另一个可变字体游乐场,具有一些非常独特的用户界面方法)