0%

Blog 9:[Hexo教程]Hexo NexT 自定义字体

三种方法为 Hexo NexT 主题自定义字体。

今天我才发现我的 NexT 主题是过时已久的 7.x 版本。尝试更新到 8.x,发现变了许多,便决定继续用旧版本了。


从 Google Fonts 引用

站点配置文件 _config.yml 中,搜索 font 字段,您将看到以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
font:
enable: true

# Uri of fonts host, e.g. https://fonts.googleapis.com (Default).
host:

# Font options:
# `external: true` will load this font family from `host` above.
# `family: Times New Roman`. Without any quotes.
# `size: x.x`. Use `em` as unit. Default: 1 (16px)

# Global font settings used for all elements inside <body>.
global:
external: true
family:
size:

# Font settings for site title (.site-title).
title:
external: true
family:
size:

# Font settings for headlines (<h1> to <h6>).
headings:
external: true
family:
size:

# Font settings for posts (.post-body).
posts:
external: true
family:

# Font settings for <code> and code blocks.
codes:
external: true
family:

host 字段处指定字体的来源,默认使用 Google Fonts。

由于不可抗力,您可使用 Google Fonts 的镜像站来确保访问速度。例如 https://fonts.loli.net

引用的字体可以分派到五个部分:全局默认网站标题博文标题博文正文内嵌代码和代码块

由于 Yaml 语法限制,此处您每个字段只能指定一种字体。

family 字段指定字体的名称。譬如 Noto Serif SC(思源宋体简体中文)。
但是,如果您需要中西文分两种字体,这显然是无法满足要求的。


修改 Stylus 样式文件

下文中将出现两个名为 base.styl 的不同文件,敬请注意区分。

首先我们必须知道是什么文件在控制 NexT 主题各元素的样式。
themes\next\source\css\_common\scaffolding\base.styl 文件中,我们可以看到类似这样的代码:

1
2
3
4
5
6
h1, h2, h3, h4, h5, h6 {
font-family: $font-family-headings;
font-weight: bold;
line-height: 1.5;
margin: 20px 0 15px;
}

很明显,这是用来指定 <h1><h6> 标签的样式的。于是我们就知道这是用来控制 NexT 主题样式的文件。注意到,这里有一个 font-family 字段。Stylus 是为 Node.js 构建的 CSS 预处理器,因此它具有 CSS 的性质。所以这里可以指定多种字体。我们只需在 $font-family-headings 前加西文字体的指定即可,比如:

1
2
3
h1, h2, h3, h4, h5, h6 {
font-family: Times New Roman, $font-family-headings;
}

这样,就为西文指定了 Times New Roman。

先指定西文字体,再指定中文字体,以确保中文字体的拉丁字符不会替换西文字体的字形。

可是什么是 $font-family-headings 呢?
打开 themes\next\source\css\_variables\base.styl 文件,我们可以看到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Font families.
$font-family-chinese = "PingFang SC", "Microsoft YaHei";

$font-family-base = $font-family-chinese, sans-serif;
$font-family-base = get_font_family('global'), $font-family-chinese, sans-serif if get_font_family('global');

$font-family-logo = $font-family-base;
$font-family-logo = get_font_family('title'), $font-family-base if get_font_family('title');

$font-family-headings = $font-family-base;
$font-family-headings = get_font_family('headings'), $font-family-base if get_font_family('headings');

$font-family-posts = $font-family-base;
$font-family-posts = get_font_family('posts'), $font-family-base if get_font_family('posts');

$font-family-monospace = consolas, Menlo, monospace, $font-family-chinese;
$font-family-monospace = get_font_family('codes'), consolas, Menlo, monospace, $font-family-chinese if get_font_family('codes');

原来,$font-family-headings 是一个变量,它先获取 _config.ymlfont 字段的 headings 设置。如果没有,则使用 $font-family-base 作为默认值。后者获取 _config.ymlfont 字段的 global 设置。如果没有,则缺省为最通用的苹方微软雅黑

所以,您如果希望正文中的西文字体是 Times New Roman,而中文是 Noto Serif SC,就可以在 _config.yml 中设置 posts 字段字体为 Noto Serif SC,然后在 控制样式base.stylbody 处指定 font-familyTimes New Roman, Noto Serif SC。其余也类似。

像上述方法在 Stylus 中指定字体时,只填写字体名称的,当浏览网页之设备有该字体时才能正常显示。如果没有,则会显示为默认字体。

如果需要指定的字体在任何设备上都能正常显示,又该如何呢?


使用 @font-face

原始方法

关于 @font-face,您可参考这里
它的格式如下:

1
2
3
4
5
6
@font-face {
font-family: "Open Sans";
src:
url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2"),
url("/fonts/OpenSans-Regular-webfont.woff") format("woff");
}

font-family 字段可以自定义字体的名称方便后续使用。src 字段指定字体文件的路径,既可以是本地路径也可以是网络路径。format 字段指定字体文件的格式,譬如 TTF。简单来说,您通过它可以自定义一个字体以供使用。

故您可以将一些字体文件上传到云端,然后以相对路径的形式引用,这样就能在任何设备上都能正常显示。在 themes\next\source 目录下新建一个 fonts 文件夹,然后将字体文件放入其中。然后在 控制样式base.styl 文件中,在 font-family 字段前加上 @font-face,如下:

1
2
3
4
@font-face {
font-family: "Mozilla Headline";
src: url("../fonts/MozillaHeadline-Regular.otf");
}

为什么是 ../fonts/?Hexo 博客在编译时,默认会将 source 目录下的所有文件复制到 public 目录下。所有样式会被编译到 public\css 目录下。对于 CSS 文件而言,OTF 文件自然是上级目录的 fonts 文件夹下的文件了。

然后再在 控制样式base.stylbody 处指定 font-familyMozilla Headline, Noto Serif SC。这样,所有设备都会在加载网页时加载 MozillaHeadline-Regular.otf 字体文件,然后应用样式。
可是,这是最优解吗?

2009 年,Web 开放字体格式出现并发展。现在正由万维网联盟的 Web 字体工作小组标准化,以求成为推荐标准。此字体格式不但能够有效利用压缩来减少档案大小,并且不包含加密也不受 DRM(数位著作权管理)限制。WOFF 本质上是包含了基于 sfnt 的字体(如 TrueType、OpenType 或开放字体格式),且这些字体均经过 WOFF 的编码工具压缩,以便嵌入网页中。这个字体格式使用zlib压缩,文件大小一般比 TTF 小 40%[1]

如果能用上 WOFF 或 WOFF2 格式,岂不美哉?

现代方法

只要能弄到 WOFF 或 WOFF2 格式的字体文件,按上述方法,就能完成速度优化。这里介绍一种从 Google Fonts 下载 WOFF 或 WOFF2 格式字体的方法。

首先,在 Google Fonts 上搜索您需要的字体。例如 Mozilla Headline。点击 Get Font,然后点击 Get embed code。

Get embed code

在 import 模式中找到字体的 URL。如下图的 https://fonts.googleapis.com/css2?family=Mozilla+Headline:wght@200..700&display=swap

Get font URL

将 URL 复制到浏览器地址栏,访问。可以得到包含 @font-face 的 CSS 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* latin-ext */
@font-face {
font-family: 'Mozilla Headline';
font-style: normal;
font-weight: 200 700;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/mozillaheadline/v1/QGY4z-UXahmCOps4kyMKGuSA9pYt2_P-w2kFrS88o6cVYTHDYMVmJQ.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Mozilla Headline';
font-style: normal;
font-weight: 200 700;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/mozillaheadline/v1/QGY4z-UXahmCOps4kyMKGuSA9pYt2_P-w2kFrS88o6cVYTHNYMU.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

这里已经包含了两个 URL,是将该字体按照不同字符集分成的两个 WOFF2 文件。浏览器访问会自动下载。将下载的文件放到 fonts 文件夹中。然后把以上代码复制到 控制样式base.styl 文件中。把 URL 改成相对路径。再在 font-family 字段中指定 Mozilla Headline,即可。

按照我的理解,直接将此 CSS 代码复制进去就能使用。但是考虑到某些不可抗力,还是建议将字体文件上传到云端,然后以相对路径的形式引用。


  1. TTF、TOF、WOFF 和 WOFF2 的相关概念 ↩︎

-------------本文结束 感谢您的时间-------------

欢迎关注我的其它发布渠道