一种新的字体规范,可显著缩减字体文件大小
在本文中,我们将介绍可变字体是什么、可变字体有哪些优势,以及如何在工作中使用可变字体。首先,我们来了解排版在 Web 上的工作原理,以及可变字体带来的创新。
浏览器兼容性
自 2020 年 5 月起,大多数浏览器都支持可变字体。请参阅我可以使用可变字体吗?和后备字体。
简介
开发者通常会将“字体”和“字体样式”这两个术语互换使用。不过,二者之间还是有区别:字体是可在许多不同排版技术中存在的底层视觉设计,而字体是这些实现之一,采用数字文件格式。换句话说,字体是您看到的,而字体是您使用的。
另一个经常被忽视的概念是样式和系列之间的区别。样式是单一且特定的字体(例如粗体斜体),字体系列则是完整的样式集。
在变体字体之前,每种样式都作为单独的字体文件实现。借助可变字体,所有样式都可以包含在一个文件中。
设计师和开发者面临的挑战
设计师在制作印刷项目时会遇到一些限制,例如页面布局的实际尺寸、可使用的颜色数量(由所使用的印刷机类型决定)等。但他们可以使用任意数量的字体样式。这意味着,平面媒体的排版通常丰富而精致,因此阅读体验非常愉悦。回想一下上次您享受浏览精彩杂志的时光。
Web 设计师和开发者面临的约束条件与平面设计师不同,其中一个重要约束条件就是设计的相关带宽费用。这一直是实现更丰富排版体验的难点,因为这需要付出代价。使用传统的 Web 字体时,设计中使用的每种样式都需要用户下载单独的字体文件,这会增加延迟时间和页面呈现时间。仅包含“Regular”和“Bold”样式以及其斜体对应项,字体数据量就可能达到 500 KB 或更多。这还只是在我们处理字体呈现方式、需要使用的后备模式或 FOIT 和 FOUT 等不良副作用之前。
许多字体系列提供更广泛的样式,从纤细到黑色粗细、窄宽和宽宽、各种样式细节,甚至针对特定大小的设计(针对大号或小号文本大小进行优化)。由于您必须为每种样式(或样式组合)加载新的字体文件,因此许多 Web 开发者选择不使用这些功能,从而降低了用户的阅读体验。
可变字体剖析
可变字体通过将样式打包到单个文件中来解决这些问题。
具体方法是从中性或“默认”样式(通常为“Regular”)开始,这种样式采用直立的罗马设计,具有最典型的粗细和宽度,最适合用于普通文本。然后,将其与连续范围内的其他样式(称为“轴”)连接起来。最常见的轴是粗细,它可以将默认样式与粗体样式相关联。任何单独的样式都可以沿轴线放置,并且称为可变字体的“实例”。有些实例由字体开发者命名,例如粗细轴位置 600 称为“粗体”。
可变字体 Roboto Flex 的 Weight 轴有三种样式。“常规”样式位于中间,轴的两端各有一种样式,一种较浅,一种较深。您可以从 900 个实例中进行选择:
字体开发者可以提供一组不同的轴。您可以将它们组合使用,因为它们都采用相同的默认样式。Roboto 在“宽度”轴上有三种样式:常规样式位于轴的中心,两种样式(较窄和较宽)位于两端。这些值提供常规样式的所有宽度,并与“粗细”轴结合使用,以提供每种粗细的所有宽度。
也就是说,有数千种样式!这可能看起来过于夸张,但这种多样化的排版样式可以显著提升阅读体验的质量。如果不会降低性能,Web 开发者可以根据自己的设计,使用少量或任意数量的样式。
斜体
可变字体中处理斜体的方式很有趣,因为有两种不同的方法。Helvetica 或 Roboto 等字体具有可插值的轮廓,因此其正体和斜体样式之间可以插值,并且可以使用倾斜度轴从正体转换为斜体。
其他字体(例如 Garamond、Baskerville 或 Bodoni)的罗马字体和斜体字符轮廓不兼容插值。例如,通常用于定义罗马小写字母“n”的轮廓与用于定义斜体小写字母“n”的轮廓不匹配。Italic 轴会从罗马风格轮廓切换到斜体轮廓,而不是将一个轮廓插值到另一个轮廓。
切换到斜体后,可供用户使用的轴应与罗马轴相同,字符集也应相同。
字形替换功能还适用于单个字形,可在可变字体的设计空间中的任何位置使用。例如,在较大的点号大小下,带有两个垂直条的美元符号设计最适合,但在较小的点号大小下,仅带有一个条的设计更好。如果用于渲染字体的像素较少,双横线设计可能会难以辨认。为了解决此问题,与“Italic”轴类似,在由排版设计师决定的某个点,Optical Size 轴上可以发生一个字形替换另一个字形的情况。
总而言之,在轮廓允许的情况下,排版设计师可以创建在多维设计空间中在各种样式之间插值的字体。这样,您就可以精细地控制排版,并获得强大的功能。
轴定义
有五个已注册的轴,用于控制字体的已知可预测特征:粗细、宽度、光学尺寸、斜度和斜体。除此之外,字体还可以包含自定义轴。这些参数可以控制字体设计师想要的字体的任何设计方面:衬线的大小、装饰线的长度、上衬线的高度或 i 上的圆点的大小。
即使轴可以控制同一项,但它们可能使用不同的值。例如,在 Oswald 和 Hepta Slab 可变字体中,只有一个轴,即粗细,但范围不同 - Oswald 的范围与升级为可变字体之前的范围相同,即 200 到 700,但 Hepta Slab 的极细粗细为 1,最高可达 900。
这五个已注册的轴都有 4 个字符的小写标记,用于在 CSS 中设置其值:
轴名称和 CSS 值 | |
---|---|
重量 |
wght
|
宽度 |
wdth
|
斜体 |
slnt
|
Optical Size |
opsz
|
斜体 |
ital
|
由于字体开发者定义了可变字体中可用的轴以及它们可以具有的值,因此了解每个字体提供的内容至关重要。字体的文档应提供此信息,或者您也可以使用 Wakamai Fondue 等工具检查字体。
使用场景和优势
设置轴值取决于个人喜好和应用排版最佳实践。任何新技术都存在可能被滥用的危险,过于艺术化或探索性的设置也可能会降低实际文本的可读性。对于标题,探索不同的轴来创作出出色的艺术设计令人兴奋,但对于正文,这可能会导致文本难以辨认。
兴奋的表情
上面展示了一个极佳的艺术表现示例,即 Mandy Michael 对字体 Decovar 的探索。
您可以点击此处查看上述示例的有效示例和源代码。
动画
您还可以探索使用可变字体为字符添加动画效果。 上图展示了将不同轴与字体 Zycon 搭配使用的示例。请参阅 Axis Praxis 上的动画实例。
Anicons 是世界上第一个基于 Material Design 图标的动画彩色图标字体。Anicons 是一项实验,它结合了两项尖端字体技术:可变字体和彩色字体。
Finesse
Roboto Flex 和 Amstelvar 提供了一组“参数轴”。在这些轴中,字母被分解为 4 个基本形式方面:黑色或正形状、白色或负形状,以及 x 和 y 尺寸。正如原色可以与任何其他颜色混合以进行调整一样,这 4 个方面也可以用于微调任何其他轴。
借助 Amstelvar 中的 XTRA 轴,您可以调整“白色”每千人次的值,如上所示。通过在相反方向使用少量 XTRA,可以使字词的宽度均衡。
CSS 中的可变字体
加载可变字体文件
可变字体通过与传统静态 Web 字体相同的 @font-face
机制加载,但具有以下两项新增强功能:
@font-face {
font-family: 'Roboto Flex';
src: url('RobotoFlex-VF.woff2') format('woff2-variations');
src: url('RobotoFlex-VF.woff2') format('woff2') tech('variations');
font-weight: 100 1000;
font-stretch: 25% 151%;
}
1. 来源格式:如果浏览器不支持可变字体,我们不希望它下载该字体,因此我们添加了 format
和 tech
说明:一次在未来语法 (format('woff2') tech('variations')
) 中,一次在已废弃但在浏览器中受支持的语法 (format('woff2-variations')
) 中。如果浏览器支持可变字体并支持即将推出的语法,则会使用第一个声明。如果它支持可变字体和当前语法,则会使用第二种声明。它们都指向同一字体文件。
2. 样式范围:您会注意到,我们为 font-weight
和 font-stretch
提供了两个值。现在,我们不再告诉浏览器此字体提供的具体粗细(例如 font-weight: 500;
),而是提供字体支持的粗细范围。对于 Roboto Flex,粗细轴的范围为 100 到 1000,CSS 会直接将轴范围映射到 font-weight
样式属性。通过在 @font-face
中指定范围,此范围之外的任何值都将被“上限”为最接近的有效值。Width 轴范围以相同的方式映射到 font-stretch
属性。
如果您使用的是 Google Fonts API,则系统会为您处理这一切。CSS 不仅包含适当的源格式和范围,Google Fonts 还会发送静态后备字体,以防系统不支持可变字体。
使用粗细和宽度
目前,您可以通过 CSS 可靠地设置的轴是通过 font-weight
设置的 wght
轴,以及通过 font-stretch
设置的 wdth
轴。
传统上,您可以将 font-weight
设置为关键字 (light
、bold
),也可以设置为介于 100 到 900 之间的数字值(以 100 为单位)。使用可变字体时,您可以在字体的宽度范围内设置任何值:
.kinda-light {
font-weight: 125;
}
.super-heavy {
font-weight: 1000;
}
同样,我们可以使用关键字 (condensed
、ultra-expanded
) 或百分比值设置 font-stretch
:
.kinda-narrow {
font-stretch: 33.3%;
}
.super-wide {
font-stretch: 151%;
}
使用斜体和斜体
ital
轴适用于同时包含普通样式和斜体样式的字体。该轴旨在作为开/关开关:值 0
处于关闭状态,并会显示常规样式,值 1
会显示斜体。与其他轴不同,此轴没有过渡。值为 0.5
不会产生“半斜体”效果。
slnt
轴与斜体不同,因为它不是新的样式,而只是将常规样式倾斜。默认情况下,其值为 0
,表示默认的竖立字母形状。Roboto Flex 的最大倾斜度为 -10 度,这意味着当从 0 变为 -10 时,字母会向右倾斜。
通过 font-style
属性设置这些轴非常直观,但截至 2020 年 4 月,我们仍在研究如何准确地执行此操作。因此,目前,您应将这些轴视为自定义轴,并通过 font-variation-settings
进行设置:
i, em, .italic {
/* Should be font-style: italic; */
font-variation-settings: 'ital' 1;
}
.slanted {
/* Should be font-style: oblique 10deg; */
font-variation-settings: 'slnt' 10;
}
使用光学尺寸
字体可以呈现为非常小(12 像素的脚注)或非常大(80 像素的标题)。字体可以通过更改字母形状来响应这些大小变化,以更好地适应其大小。小尺寸的图片可能不适合添加精细的细节,而大尺寸的图片则可能需要添加更多细节和更细的笔触。
为此轴引入了新的 CSS 属性:font-optical-sizing
。默认情况下,它设置为 auto
,这会使浏览器根据 font-size
设置轴值。这意味着浏览器会自动选择最佳光学尺寸,但如果您想关闭此功能,可以将 font-optical-sizing
设为 none
。
如果您刻意希望光学尺寸与字号不匹配,还可以为 opsz
轴设置自定义值。以下 CSS 会导致文本以较大的尺寸显示,但光学尺寸就像是用 8pt
打印的:
.small-yet-large {
font-size: 100px;
font-variation-settings: 'opsz' 8;
}
使用自定义轴
与注册的轴不同,自定义轴不会映射到现有的 CSS 属性,因此您始终必须通过 font-variation-settings
进行设置。自定义轴的标记始终采用大写形式,以便与已注册的轴区分开来。
Roboto Flex 提供了一些自定义轴,其中最重要的是 Grade (GRAD
)。Grade 轴很有趣,因为它会更改字体的粗细,而不会更改宽度,因此换行符不会发生变化。通过调整“Grade”轴,您可以避免被迫调整影响整体宽度的“Weight”轴,然后再调整影响整体粗细的“Width”轴。
由于 GRAD
是自定义轴,在 Roboto Flex 中的范围为 -200 到 150。我们需要使用 font-variation-settings
解决此问题:
.grade-light {
font-variation-settings: `GRAD` -200;
}
.grade-normal {
font-variation-settings: `GRAD` 0;
}
.grade-heavy {
font-variation-settings: `GRAD` 150;
}
Google Fonts 中的可变字体
Google Fonts 已在其目录中添加了可变字体,并会定期添加新字体。该界面目前旨在从字体中选择单个实例:您选择所需的变体,点击“选择此样式”,该变体将添加到从 Google Fonts 提取 CSS 和字体的 <link>
元素。
如需使用所有可用的轴或值范围,您必须手动组合 Google Fonts API 的网址。可变字体概览列出了所有轴和值。
Google 可变字体链接工具还可以为您提供完整可变字体的最新网址。
font-variation-settings 继承
虽然所有已注册的轴很快就会通过现有 CSS 属性得到支持,但目前您可能需要依赖 font-variation-settings
作为回退。如果您的字体具有自定义轴,您还需要 font-variation-settings
。
不过,font-variation-settings
有一个小问题。您未明确设置的每个属性都将自动重置为默认值。之前设置的值不会被继承!这意味着以下操作将无法正常运行:
<span class="slanted grade-light">
I should be slanted and have a light grade
</span>
首先,浏览器会应用 .slanted
类中的 font-variation-settings: 'slnt' 10
。然后,它将应用 .grade-light
类中的 font-variation-settings: 'GRAD' -200
。不过,这会将 slnt
重置为默认值 0!结果将是浅色文本,但不会倾斜。
幸运的是,我们可以使用 CSS 变量来解决此问题:
/* Set the default values */
:root {
--slnt: 0;
--GRAD: 0;
}
/* Change value for these elements and their children */
.slanted {
--slnt: 10;
}
.grade-light {
--grad: -200;
}
.grade-normal {
--grad: 0;
}
.grade-heavy {
--grad: 150;
}
/* Apply whatever value is kept in the CSS variables */
.slanted,
.grade-light,
.grade-normal,
.grade-heavy {
font-variation-settings: 'slnt' var(--slnt), 'GRAD' var(--GRAD);
}
CSS 变量会级联,因此,如果某个元素(或其某个父元素)将 slnt
设置为 10
,则即使您将 GRAD
设置为其他值,该元素也会保留该值。如需详细了解此方法,请参阅修复可变字体继承问题。
请注意,CSS 变量无法设置动画(这是设计使然),因此以下代码不起作用:
@keyframes width-animation {
from { --wdth: 25; }
to { --wdth: 151; }
}
这些动画必须直接在 font-variation-settings
上进行。
效果提升
借助 OpenType 可变字体,我们可以将字体系列的多个变体存储在单个字体文件中。Monotype 开展了一项实验,通过组合 12 种输入字体,在三种宽度和斜体和罗马风格中生成了八种粗细。在单个可变字体文件中存储 48 种单独的字体意味着文件大小缩减了 88%。
不过,如果您只使用 Roboto Regular 等单一字体,那么切换到具有多个轴的可变字体后,字体大小可能不会有明显的增加。一如既往,这取决于您的使用场景。
另一方面,在不同设置之间为字体添加动画效果可能会导致性能问题。虽然在浏览器中对可变字体的支持更加成熟后,此问题会有所改善,但通过仅为当前屏幕上的字体添加动画效果,也可以在一定程度上减少此问题。Dinamo 提供了以下实用代码段,可在类为 vf-animation
的元素不在屏幕上时暂停这些元素中的动画:
var observer = new IntersectionObserver(function(entries, observer) {
entries.forEach(function(entry) {
// Pause/Play the animation
if (entry.isIntersecting) entry.target.style.animationPlayState = "running"
else entry.target.style.animationPlayState = "paused"
});
});
var variableTexts = document.querySelectorAll(".vf-animation");
variableTexts.forEach(function(el) { observer.observe(el); });
如果您的字体会响应用户互动,最好对输入事件进行节流或去抖。这将防止浏览器渲染与上一个实例变化如此之小(人眼无法察觉到差异)的可变字体实例。
如果您使用的是 Google Fonts,不妨预连接到 https://fonts.gstatic.com
(Google 字体的托管网域)。这样可以确保浏览器在 CSS 中遇到字体时,能够尽早知道从何处获取这些字体:
<link rel="preconnect" href="https://fonts.gstatic.com" />
此提示也适用于其他 CDN:您让浏览器设置网络连接的时间越早,它下载字体的速度就越快。
如需了解有关加载 Google Fonts 的更多性能提示,请参阅最快的 Google Fonts。
回退和浏览器支持
所有现代浏览器都支持可变字体。如果您需要支持旧版浏览器,可以选择使用静态字体构建网站,并将可变字体用作渐进增强功能:
/* Set up Roboto for old browsers, only regular + bold */
@supports not (font-variation-settings: normal) {
@font-face {
font-family: Roboto;
src: url('Roboto-Regular.woff2');
font-weight: normal;
}
@font-face {
font-family: Roboto;
src: url('Roboto-Bold.woff2');
font-weight: bold;
}
body {
font-family: Roboto;
}
.super-bold {
font-weight: bold;
}
}
/* Set up Roboto for modern browsers, all weights */
@supports (font-variation-settings: normal) {
@font-face {
font-family: 'Roboto';
src: url('RobotoFlex-VF.woff2') format('woff2 supports variations'),
url('RobotoFlex-VF.woff2') format('woff2-variations');
font-weight: 100 1000;
font-stretch: 25% 151%;
}
.super-bold {
font-weight: 1000;
}
}
对于旧版浏览器,类为 .super-bold
的文本将以正常粗体显示,因为这是我们唯一提供的粗体字体。在支持可变字体的情况下,我们实际上可以使用最粗的粗细 1000。
Internet Explorer 不支持 @supports
规则,因此此浏览器不会显示任何样式。如果遇到此问题,您可以随时使用某种老式黑客攻击来定位相关的旧版浏览器。
如果您使用的是 Google Fonts API,该 API 会负责为访问者的浏览器加载适当的字体。假设您请求粗细范围为 200 到 700 的字体 Oswald,如下所示:
<link href="https://fonts.googleapis.com/css2?family=Oswald:wght@200..700&display=swap" rel="stylesheet">
能够处理可变字体的新型浏览器将会获取可变字体,并且可使用介于 200 到 700 之间的所有粗细。旧版浏览器将针对每种粗细分别获取静态字体。在本例中,这意味着他们将下载 6 个字体文件:一个粗细为 200,一个粗细为 300,依此类推。
谢谢
以下人员对本文的撰写提供了帮助:
- Mustafa Kurtuldu,Google 的用户体验设计师和设计推广工程师
- Roel Nieskens,Kabisa 的用户体验设计师/开发者和排版专家
- Dave Crossland,Google Fonts 项目经理
- David Berlow,Font Bureau 的排版设计师和排版师
- Laurence Penney,axis-praxis.org 的开发者
- Mandy Michael,variablefonts.dev 的开发者
主打图片由 Unsplash 用户 Bruno Martins 提供。