如果我们想使用一种不是预先安装在用户设备上的字体,我们可以下载并使用自定义Web字体!本文介绍几种实现方式。
使用Google字体
谷歌字体是一个免费的、开源的网络字体库,它们有数百种流行的选择。
它还可以有效地作为字体的 CDN; 它们通过自己的服务器为我们提供字体。
谷歌字体的工作原理是提供这样一个代码片段:
<link rel="preconnect" href="<https://fonts.gstatic.com>">
<link href="<https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@1,400;1,600&display=swap>" rel="stylesheet">
把它放到 HTML 文件的 `` 中。
这个代码片段会下载一个样式表来下载一个字体,我们可以在 CSS 中访问这个字体:
.thing {
font-family:'Open Sans', sans-serif;
}
Web 字体应该用引号包装(“Open Sans”,而不是Open Sans)。如果你的Web字体是一个单词,这并不是严格要求的,但它是一个有用的约定: 它指出堆栈中的字体是Web字体还是本地字体。
谷歌字体的主要好处是它很漂亮,很容易使用。缺点是很多令人惊叹的字体在谷歌字体上是无法使用;自我托管的Web字体反而性能更好。
Gatsby的创始人Kyle Matthews发现,自托管字体可以在桌面设备上节省300毫秒,在移动3G设备上节省1秒以上。
为什么使用Goolge字体反而会更慢呢?抛开网络环境因素(墙)和服务器因素(Google的服务器肯定是性能很好的),其实主要原因还是Google字体的使用方式。
让我们来看看使用上面Google的HTTP代码会发生什么:
- 浏览器解析
index.html
文件 - 当解析到
<link href="https://fonts.googleapis.com/css2">
标签时,会发送一个HTTP请求来获取CSS文件 - 浏览器解析CSS文件,发现有Web字体需要下载,于是从发送请求到 fonts.gstatic.com 来获取字体文件。
从上面的步骤可以看到CSS文件与字体文件是放置在不同的外部域名上的,这就不可避免的增加了网络开销(如HTTP三次握手)。而对CSS文件的请求是会阻塞页面渲染的。相比之下自托管的Web字体反而更有优势,因为它可以将CSS内嵌到HTML文件中,跳过了其中的的第二步;并且字体文件存储在同一服务器上,也可以减少很多网络开销(减少了握手次数)
在过去,浏览器有一个全局缓存可以抵消这一点; 有可能你的用户已经有一个缓存版本的字体,因为不同的站点从同一个 CDN 获取了字体。然而,出于隐私方面的考虑,浏览器已经开始使用分区缓存。这意味着你的用户在第一次访问时总是需要下载你的网页字体,即使他们已经访问的其他网站使用了从相同的CDN获取的相同字体。
使用Fontsource打包字体
Next.js框架背后的公司Vercel发布了一个有趣的免费的制作自托管字体资源Fontsource。
它提供了一个易于使用的方法来安装和使用自托管的 web 字体。它是专门为现代 JS 应用程序构建的,让你 NPM 安装你想要使用的字体。它们支持所有的 Google 字体,以及额外的免费开源字体。
手动方式
如果你想使用 Google 字体或者 Fontsource 上没有的字体,该怎么办?
那就可以通过手动的方式添加了
转换格式
在我们的电脑上运行的字体通常是.otf
或 .ttf
文件格式。这些文件格式不适合在web上使用,而且它们的文件往往相对庞大。
我们首先必须将我们的字体转换成一种web友好的格式。你可以使用在线转换工具,比如 Fontsquirrel 的 webfont generator。
font-face
接下来我们使用@font-face
来告诉浏览器我们想要使用的web字体:
@font-face {
font-family: 'Wotfard';
src: url('/fonts/wotfard-regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Wotfard';
src: url('/fonts/wotfard-medium.woff2') format('woff2');
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: 'Wotfard';
src: url('/fonts/wotfard-bold.woff2') format('woff2');
font-weight: 700;
font-style: normal;
}
@font-face {
font-family: 'Wotfard';
src: url('/fonts/wotfard-regular-italic.woff2') format('woff2');
font-weight: 400;
font-style: italic;
}
我们需要多个语句,因为每个字体的weight和样式都有自己的文件。在本例中,我加载了3种不同的字体(常规字体、中等字体和粗体字体) ,以及一种用于常规字体的斜体变体。
字体文件本身不包含任何关于它的weight/样式的“元数据”,因此我们需要将它们链接起来。@font-face
语句中的所有声明需要做的。我们为一组字符指定源(src
),然后指定与该字符集相关联的元数据(font-family
、 font-weight
、 font-style
)。
支持IE
在过去,我们需要为每个字符集提供3或4个字体文件,因为不同的浏览器支持不同的格式。
现在,事情变得好多了。.woff2
格式是一种现代的、经过高度优化的格式,可以在所有主流浏览器上使用,但不适用于 IE。
如果你希望 IE 用户可以访问 web 字体,你需要指定一个.woff
格式的作为回退。
如果你使用 web 字体生成器或者下载了 web 字体包,你应该已经有了这个文件。他们通常会把你的字体转换成几种常见的格式。
在@font-face
语句中,可以包含多个来源:
@font-face {
font-family:'Wotfard';
src: url('/fonts/wotfard-regular-italic.woff') format('woff'),
url('/fonts/wotfard-regular-italic.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
一定要把它们按这个顺序排列,以便.woff2
排在最后; 浏览器将下载最终的可识别格式,我们希望现代浏览器使用.woff2
(它倾向于生成较小的文件系统)。
当浏览器解析这些@font-face
语句时,将获取并加载 src
下声明的字体文件。你可以像使用任何字体一样使用 CSS 中的字体:
.something {
font-family:'Wotfard';
font-weight: 400;
}
伪粗体与斜体
@ font-face
语句允许我们将特定的字体权重值(比如700)连接到字符集。当我们使用font-weight: bold或font-weight: 700时,浏览器将使用粗体。
但是如果我们使用的字体没有相应的粗体字符集会发生什么呢?
浏览器会创建“为粗体”文本,它通过加粗每个字体中的线条来实现。这往往会让文字看上去有点模糊。可以看看下面字体中自带的粗体与浏览器生成的“伪粗体”的对比:
真正的粗体(字体文件中自带的)
浏览器生成的“伪粗体”
当字体设计师创建字体的粗体变体时,他们会有意地和策略性地改变字符,优化美感和可读性。浏览器生成的伪粗体要简单粗暴得多,它们只是使线条更粗。
类似地,当提到斜体字时,浏览器只是简单地倾斜字母,而真正的斜体字使用替换字符:
真正的斜体
浏览器生成的“伪斜体”
font-weight的四舍五入
现代浏览器在遇到其字体文件中不存在的font-weight值的字符集是,采用的“四舍五入”的策略。
假设我们决定从 web 字体中包含两种字体样式: 400 weight 和800 weight。
当你使用“bold”字体时会发生什么?
.thing {
font-weight: bold;
}
或者,如果你设置的数值在字体文件中没有对应的字符集呢?
.thing {
font-weight: 700;
}
在现代浏览器之前,精确度非常重要。这两种声明都会导致浏览器直接加粗 400 weight的字体而不是使用800 weight的字体。
而现代浏览器将使用800 weight的字体。