木匣子

Web/Game/Programming/Life etc.

中文博客的字体选型

去年五月份制作这个主题的时候,特别研究了一下博客字体的选型,当时想写个博客记录一下,但是因为曦仔出生后比较忙就忘了。

如今 JetBrains Mono 发布后有一段时间了,在 IDE 中使用了几个星期,感觉非常好。于是想把它放到博客上用,也趁机把这篇博客整理出来。

如果是纯英文博客的话,选字体的事情比较好办,因为直接引入 Web Fonts 的成本非常低(文件小),而且现在 Web Fonts 的兼容性很好,基本上所有主流浏览器都支持。于是只要选择几款好看的 Web Fonts 就能保证各个平台所用的字体的一致性。

但是对于中文博客来说,使用 Web Font 的使用成本太高了。由于中文的复杂性,每个汉字都有专门的字形,而非像拉丁文一样由一些基本字母符号组成单词,这就导致中文字体文件非常之大。所以中文 Web Font 很难流行起来。

于是,中文博客的字体选型最安全的作法,就是从各平台的系统字体中选择可以用的方案。不过对于博客中的代码片段,我们仍然可以选择喜欢的专用字体。

首先,字体可以分为两个大类:衬线字体(Serif)与非衬线字体(Sans-Serif)。虽然我对字体的感受并不是非常深刻,但是常年使用下来的简单感受可以总结如下:

非衬线字体适用于短文和屏幕内容,代表字体是黑体。可以用在较理性的技术类文章。

衬线字体适用于较长的书面文件,尤其是打印文本,代表字体是宋体。可以用在较感性的生活随笔类文章中。

所以我博客的大部分内容以非衬线黑体为基调,只有少数几篇文章使用了衬线体,例如《写在 2019 年末》。我在模版中使用了如下设置,用于切换正文字体类型。

---
typography: serif
---

那么我们如何为博客选择字体呢?首先我们需要知道操作系统默认为我们提供了哪些选择。可以通过查询各个系统发行版的字体,例如 macOS Mojave 附带的字体,但是这样过于繁琐。好在有人在维基百科整理了这个页面,列出了常见的不同系统自带的日中韩字体:List Of CJK fonts。从这个列表中我们可以找到大量的 Sans-Serif/Serif 中文字体。

以非衬线体为例,我们可以找到:

  • OSX 10.2+: 华文黑体 STHeiti
  • OSX 10.6+: 黑体-简 Heiti SC / 黑体-繁 Heiti TC
  • OSX 10.6+: 冬青黑体简体中文 Hiragino Sans GB
  • OSX 10.11+: 苹方-简 PingFang SC / 苹方-繁 PingFang TC
  • Windows XP+: MS Hei 微软黑体
  • Windows Vista+: Microsoft YaHei 微软雅黑
  • Open Source*: WenQuanYi Zen Hei 文泉驿正黑
  • Open Source*: WenQuanYi Micro Hei 文泉驿微米黑
  • Open Source*: Noto Sans CJK / Source Han Sans

苹果系统自带了数款黑体,虽然都是黑体,但是细节上并不相同,给人的感觉也不太一样。我查看了一下 Font Book(苹果自带的字体查看器),苹方、黑体、冬青黑体都是预安装,但是华文黑体虽然可用,但未预安装。个人比较喜欢苹方和冬青黑。

微软雅黑在 Windows 表现非常好,已经家喻户晓。基本已经代替微软黑体。

Linux 由于发行版众多,比较混乱,一般需要用户自行安装中文字体,常见的有文泉驿、思源等开源字体。

Android 目前使用 Adobe 和 Google 联合开发的思源系列 Source * 字体,不过在 Android 中叫做 Noto *

iOS 使用与 macOS 相同的中文字体。详见苹果官网的字体列表

同理我们可以找到相应的中文衬线字体,这里就不再列举了。

但是要注意的是,iOS 系统并不预装 CJK 衬线字体。所以几乎所有的中文网页在 iOS 都是显示为非衬线字体。原因正是前文所说的,黑体在屏幕上的可读性比宋体要高。

以下是当前主题使用的字形选型:

$fonts-sans-serif: Roboto, Helvetica, Tahoma, Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Noto Sans CJK", sans-serif;
$fonts-serif: Georgia, "Times New Roman", PMingLiu, STSong, SimSun, "WenQuanYi Bitmap Song", "Noto Serif CJK", serif;
$fonts-monospace: JetBrainsMono, "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", Courier, monospace;

CSS 中的 font-famil 属性,会按每个字符,依次从左向右遍历列表,直到找到第一个可用的字体,则使用该字体渲染文字。

根据这个规则,我把英文字体优先放在前面,因为我希望英文优先使用指定的英体而非中文字体中的英语字形(并不好看)。而中文字符在英文字体中找不到对应字形,则会落到后面备用的中文字体中选择。此外依照不同系统,从高版本到低版本排序,保证使用较新系统的人可以使用较新的字体。最后使用浏览器默认的 fallback 字体作结尾。

如果写博客的风格会夹杂繁简体中文,而字体是区分的繁简的话,最好把两种字体都加上。

最后来讲讲等宽字体(monospace)。等宽字体顾名思义,每个字符具有相同的宽度,这使得英文字符和标点总是工整地排列,非常适合代码布局。为了提升代码的可读性,这些字体还专门为一些字母和符号做了优化,让你一眼就可以区别出 O0 / 1ilIL

最近几年有一些优秀的专为编程而开发的开源字体问世,例如 Source Code ProJetbrains Mono

对于开源字体,如果能在 Google Fonts 直接找到的话,可以通过他们的 CDN 直接引用到页面上。例如 Source Code Pro

<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro&display=swap" rel="stylesheet">

或者

<style>
@import url('https://fonts.googleapis.com/css?family=Source+Code+Pro&display=swap');
</style>

如果找不到免费的 CDN 的话,也可以下载字体文件部署到自己的服务器上。例如 Jetbrains Mono。下载解后,将 web 目录下的字体按需复制到 Web 项目中:

~/Downloads/JetBrainsMono-1.0.2
├── ttf
│   ├── JetBrainsMono-Bold-Italic.ttf
│   ├── JetBrainsMono-Bold.ttf
│   ├── JetBrainsMono-ExtraBold-Italic.ttf
│   ├── JetBrainsMono-ExtraBold.ttf
│   ├── JetBrainsMono-Italic.ttf
│   ├── JetBrainsMono-Medium-Italic.ttf
│   ├── JetBrainsMono-Medium.ttf
│   └── JetBrainsMono-Regular.ttf
└── web
    ├── eot
    │   ├── JetBrainsMono-Bold-Italic.eot
    │   ├── JetBrainsMono-Bold.eot
    │   ├── JetBrainsMono-ExtraBold-Italic.eot
    │   ├── JetBrainsMono-ExtraBold.eot
    │   ├── JetBrainsMono-Italic.eot
    │   ├── JetBrainsMono-Medium-Italic.eot
    │   ├── JetBrainsMono-Medium.eot
    │   └── JetBrainsMono-Regular.eot
    ├── woff
    │   ├── JetBrainsMono-Bold-Italic.woff
    │   ├── JetBrainsMono-Bold.woff
    │   ├── JetBrainsMono-ExtraBold-Italic.woff
    │   ├── JetBrainsMono-ExtraBold.woff
    │   ├── JetBrainsMono-Italic.woff
    │   ├── JetBrainsMono-Medium-Italic.woff
    │   ├── JetBrainsMono-Medium.woff
    │   └── JetBrainsMono-Regular.woff
    └── woff2
        ├── JetBrainsMono-Bold-Italic.woff2
        ├── JetBrainsMono-Bold.woff2
        ├── JetBrainsMono-ExtraBold-Italic.woff2
        ├── JetBrainsMono-ExtraBold.woff2
        ├── JetBrainsMono-Italic.woff2
        ├── JetBrainsMono-Medium-Italic.woff2
        ├── JetBrainsMono-Medium.woff2
        └── JetBrainsMono-Regular.woff2

因为我只需要在代码片段中使用这个字体,所以只需要 JetBrainsMono-Regular.*。将其复制到 assets/fonts 目录:

./source/assets
├── fonts
│   ├── JetBrainsMono-Regular.eot
│   ├── JetBrainsMono-Regular.ttf
│   ├── JetBrainsMono-Regular.woff
│   └── JetBrainsMono-Regular.woff2
└── style.css

然后在 style.css 中加入兼容各个浏览器的 @font-face 定义:

@font-face {
    font-family: "JetBrains Mono";
    src: url("./fonts/JetBrainsMono-Regular.eot");
    src: url("./fonts/JetBrainsMono-Regular.eot?#iefix") format("embedded-opentype"),
        url("./fonts/JetBrainsMono-Regular.woff2") format("woff2"),
        url("./fonts/JetBrainsMono-Regular.woff") format("woff"),
        url("./fonts/JetBrainsMono-Regular.ttf") format("truetype");
    font-weight: 400;
    font-style: normal;
}

之后便可以在 CSS 中使用该字体:

.code {
    font-family: "JetBrains Mono", monospace;
}

这样浏览器就会下载自己能使用的字体文件进行文字渲染了。


Update 2020-02-18:

今天更新主题的时候发现 Jetbrains Mono 的字体炸了,好多字形在 Safari/iOS 上不能正常显示。查了半天发现字体文件提交到 git 上再重新检出后 md5 变了。原来是因为配置 .gitattributes 文件把字体文件当文本,将里面的 \r\n 字节作了转换,破坏了字体文件。在 .gitattributes 增加以下配置,再重新提交字体即可修复。

* text eol=lf
*.eot binary
*.ttf binary
*.woff binary
*.woff2 binary