突破限制,CSS font-variation 可变字体的魅力
共 13461字,需浏览 27分钟
·
2022-03-08 08:54
作者:chokcoco
来源:SegmentFault 思否社区
今天,在 CodePen 上看到一个很有意思的效果 -- GSAP 3 ETC Variable Font Wave
预览链接:https://codepen.io/Chokcoco/pen/BamYMYg
借助了 JS 动画库 GSAP 实现,一起来看看:
我寻思着能否使用 CSS 复刻一版,鼓捣了一会,利用纯 CSS 成功实现了原效果。
上述效果,最核心的就是文字的动画,文字从较细贴着较紧,到较粗隔着较远不断变化。有人会认为这里是 transform: scale(),实则不然。
scale 是等比例放大缩小一个物体,而仔细观察上述效果,明显是有字体的粗细、字体的字宽的变化。这里,其实用到了 CSS 比较新的特性 -- 可变字体,也就是 font-variation。
本文,将借助这个效果,介绍一下什么是 CSS font-variation。
什么是 CSS font-variation,可变字体?
根据 MDN -- Variable fonts,可变字体(Variable fonts)是 OpenType 字体规范上的演进,它允许将同一字体的多个变体统合进单独的字体文件中。从而无需再将不同字宽、字重或不同样式的字体分割成不同的字体文件。我们只需通过CSS与一行 @font-face 引用,即可获取包含在这个单一文件中的各种字体变体。
emm,概念有点难理解,简单解释一下。
与可变字体对应的,是标准(静态)字体。
标准(静态)字体就是只代表字体的某一特定的宽度/字重/样式的组合的字体文件,通常我们在页面引入的字体文件都是这种,只代表这个字体的某一特定的宽度/字重/样式的组合。
而如果我们想引入一个字体家族(譬如 Roboto 字体族),它可能包含了 “Roboto Regular”(常规字重)、“Roboto Bold”(粗体),或是 “Roboto Bold Italic”(粗体+斜体) 等一系列字体文件。这意味着我们可能需要 20 或 30 个不同的字体文件才能算是有了一整个字体家族(对于有着不同宽度的大型字体来说,这个数量还要翻上几倍)。
而可变字体 -- font-variation,可以将它理解为 all in one,通过使用可变字体,所有字重、字宽、斜体等情况的排列组合都可以被装进一个文件中。当然,这个文件可能比常规的单个字体文件大一些。
静态字体的局限性
举个例子,在 Google Font,我随便选取一个标准静态字体,实现一个字体 font-weight 的变化动画:
<p>CSS font-variation</p>
<p>CSS font-variation</p>
<p>CSS font-variation</p>
<p>CSS font-variation</p>
<p>CSS font-variation</p>
<p>CSS font-variation</p>
@import url('https://fonts.googleapis.com/css2?family=Lato:wght@300&display=swap');
p {
font-family: 'Lato', sans-serif;
font-size: 48px;
}
p:nth-child(1) {
font-weight: 100;
}
p:nth-child(2) {
font-weight: 200;
}
p:nth-child(3) {
font-weight: 300;
}
p:nth-child(4) {
font-weight: 400;
}
p:nth-child(5) {
font-weight: 500;
}
p:nth-child(6) {
font-weight: 600;
}
看看结果:
并没有我们想象中的,因为字体粗细从 100 到 600,所以字体依次变粗的情况,一共只有两种字重:
当 font-weight: 处于 100 - 500 的时候,其实都是 font-weight: normal;
当 font-weight: 600 的时候,其实是命中了 font-weight: bold。
可变字体的多样性
@font-face {
font-family: 'Anybody';
src: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/61488/ETCAnybodyPB.woff2') format('woff2-variations');
font-display: block;
font-style: normal italic;
font-weight: 100 900;
font-stretch: 10% 400%;
}
p {
font-family: 'Anybody', sans-serif;
font-size: 48px;
}
p:nth-child(1) {
font-weight: 100;
}
// ...
p:nth-child(6) {
font-weight: 600;
}
理解 font-variation-settings
字重轴 "wght":对应 font-weight,控制字体的粗细
宽度轴 "wdth":对应 font-stretch,控制字体的伸缩
斜度轴 "slnt" (slant):对应字体的 font-style: oblique + angle,控制字体的倾斜
斜体轴 "ital":对应字体的 font-style: italic,控制字体的倾斜(注意,和 font-style: oblique 是不一样的倾斜)
光学尺寸轴 "opsz":对应字体的 font-optical-sizing,控制字体的光学尺寸
<p>Anybody</p>
@font-face {
font-family: 'Anybody';
src: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/61488/ETCAnybodyPB.woff2') format('woff2-variations');
font-display: block;
font-style: normal italic;
font-weight: 100 900;
font-stretch: 10% 400%;
}
p {
font-family: 'Anybody';
font-size: 48px;
animation: fontWeightChange 2s infinite alternate linear;
}
@keyframes fontWeightChange {
0% {
font-variation-settings: 'wght' 100;
}
100% {
font-variation-settings: "wght" 600;
}
}
利用 font-variation-settings 进行字体的多个特征同时变化
<p>Anybody</p>
@font-face {
font-family: 'Anybody';
src: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/61488/ETCAnybodyPB.woff2') format('woff2-variations');
font-display: block;
font-style: normal italic;
font-weight: 100 900;
font-stretch: 10% 400%;
}
p {
font-family: 'Anybody';
font-size: 48px;
animation: fontWeightChange 2s infinite alternate linear;
}
@keyframes fontWeightChange {
0% {
font-variation-settings: 'wght' 100, 'wdth' 60;
}
100% {
font-variation-settings: "wght" 600, 'wdth' 400;
}
}
<div class="g-container">
<ul>
<li>ANYBODY</li>
<li>ANYBODY</li>
<li>ANYBODY</li>
<li>ANYBODY</li>
<li>ANYBODY</li>
<li>ANYBODY</li>
<li>ANYBODY</li>
<li>ANYBODY</li>
</ul>
</div>
li {
animation: change 0.8s infinite linear alternate;
}
@for $i from 1 to 9 {
li:nth-child(#{$i}) {
animation-delay: #{($i - 1) * -0.125}s;
}
}
@keyframes change {
0% {
font-variation-settings: 'wdth' 60, 'wght' 100;
opacity: .5;
}
100% {
font-variation-settings: 'wdth' 400, 'wght' 900;
opacity: 1;
}
}
@font-face {
font-family: 'Anybody';
src: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/61488/ETCAnybodyPB.woff2') format('woff2-variations');
font-display: block;
font-style: normal italic;
font-weight: 100 900;
font-stretch: 10% 400%;
}
.g-container {
position: relative;
margin: auto;
display: flex;
font-size: 48px;
font-family: 'Anybody';
color: #fff;
transform-style: preserve-3d;
perspective: 200px;
}
ul {
background: radial-gradient(farthest-side at 110px 0px, rgba(255, 255, 255, 0.2) 0%, #171717 100%);
padding: 5px;
transform-style: preserve-3d;
transform: translateZ(-60px) rotateX(30deg) translateY(-30px);
animation: move 3s infinite alternate;
&::before {
content: "";
position: absolute;
left: 0;
bottom: 0;
right: 0;
height: 45px;
background: #141313;
transform: rotateX(-230deg);
transform-origin: 50% 100%;
}
}
li {
width: 410px;
animation: change 0.8s infinite linear alternate;
}
@for $i from 1 to 9 {
li:nth-child(#{$i}) {
animation-delay: #{($i - 1) * -0.125}s;
}
}
@keyframes change {
0% {
font-variation-settings: 'wdth' 60, 'wght' 100;
opacity: .5;
}
100% {
font-variation-settings: 'wdth' 400, 'wght' 900;
opacity: 1;
}
}
@keyframes move {
100% {
transform: translateZ(-60px) rotateX(30deg) translateY(0px);
}
}
font-variation 的可变轴 -- 注册轴与自定义轴
注册轴 - registered axes 自定义轴 - custom axes
注册轴最为常见,常见到制定规范的作者认为有必要进行标准化。目前注册的五个轴是字重,宽度,倾斜度,斜体和光学尺寸。
字重轴 "wght":对应 font-weight,控制字体的粗细
宽度轴 "wdth":对应 font-stretch,控制字体的伸缩
斜度轴 "slnt" (slant):对应字体的 font-style: oblique + angle,控制字体的倾斜
斜体轴 "ital":对应字体的 font-style: italic,控制字体的倾斜(注意,和 font-style: oblique 是不一样的倾斜)
光学尺寸轴 "opsz":对应字体的 font-optical-sizing,控制字体的光学尺寸
自定义轴实际上是无限的:字体设计师可以定义和界定他们喜欢的任何轴,并且只需要给它一个四个字母的标签以在字体文件格式本身中识别它。
<p>Grade</p>
p {
font-family: "Amstelvar VF", serif;
font-size: 64px;
font-variation-settings: 'GRAD' 88;
}
等级轴 'GRAD':“等级”一词指的是字体设计的相对重量或密度,但与传统的“重量”不同之处在于文本占据的物理空间不会改变,因此改变文本等级并不会改变文本或其周围元素的整体布局。这使得等级成为有用的变化轴,因为它可以变化或动画而不会引起文本本身的回流。
去哪找可变字体?
这里有一个很不错的网站 -- Variable Fonts:https://v-fonts.com/
上面收集了非常多的 Variable Fonts,并且罗列出了它们在注册轴上支持的字体属性的范围,譬如支持字重从 100 到 700,我们可以自由进行调试预览