站点自定义:字体配置(以霞鹜文楷为例)

学习目标

  • 理解 Quartz v5 站点的字体配置链路(两套系统 + 优先级)
  • 掌握为站点引入 Google Fonts 之外 的字体(CDN 方式)
  • 学会本地构建验证与提交发布流程

前置条件

1. 为什么要单独配置字体

Quartz 默认通过 Google Fonts 加载 theme.typography 中指定的字体(本教程默认 Noto Sans SC / JetBrains Mono)。但很多优秀的中文字体并不在 Google Fonts 上,例如:

  • 霞鹜文楷(LXGW WenKai):开源楷体风格字体,仓库 lxgw/LxgwWenKai
  • 直接把它填进 typography.header 会怎样?og-image 插件构建时去 Google Fonts 抓取会失败/警告,页面也不会有该字体

针对这类字体有两种接入方案:

方案做法优点缺点
CDN 引入(本教程采用)<head> 挂一张样式表,字体文件由 CDN 按需下发改动小、维护简单依赖第三方 CDN(jsDelivr)
自托管把 woff2 放进 quartz/static/,CSS 引用自己域名完全离线、可控需下载约 120 个子集文件

本项目采用 CDN 方案:字体包 lxgw-wenkai-webfont 已发布到 npm,用 jsDelivr 直接引用即可:https://cdn.jsdelivr.net/npm/lxgw-wenkai-webfont@1.7.0/style.min.css

2. 先搞清字体配置链路

Quartz v5 有两套字体系统,容易混淆:

系统位置作用
核心主题quartz.config.yamltheme.typography + theme.fontOrigin<head> 注入 Google Fonts 链接;variables.scss 据此生成 --titleFont/--headerFont/--bodyFont/--codeFont 变量(无 layer,优先级最高)
字体插件@quartz-community/quartz-fonts(已内置启用)更细粒度控制(h1–h6 独立字体);生成的变量在 @layer quartz-fonts 中,优先级低于核心

因此结论是:custom.scss 里写一个 unlayered 的 :root 覆盖字体变量,一定生效(同优先级下位置靠后者胜出)。这正是本方案的核心思路。

3. 步骤一:在 <head> 注入 CDN 样式表

编辑 quartz/components/Head.tsx,在 Google Fonts 注入块之后加上:

{/* 霞鹜文楷(LXGW WenKai)webfont,通过 jsDelivr CDN 按 unicode-range 子集加载 */}
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossOrigin="anonymous" />
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/lxgw-wenkai-webfont@1.7.0/style.min.css"
/>

:为什么不能把 @import url("https://...") 写进 custom.scss
Quartz 构建时会把所有 SCSS 打包成一个 CSS 文件,@import 不在文件头部,会被 CSS 打包器拒绝,报错:
@import rules must precede all rules aside from @charset and @layer statements
所以外部样式表必须走 <head><link>

4. 步骤二:覆盖字体变量

编辑 quartz/styles/custom.scss,在 @use 之后追加:

// 用霞鹜文楷覆盖站点字体(unlayered 变量,优先级最高)
:root {
  --titleFont: "LXGW WenKai", system-ui, "Segoe UI", Roboto, sans-serif;
  --headerFont: "LXGW WenKai", system-ui, "Segoe UI", Roboto, sans-serif;
  --bodyFont: "LXGW WenKai", system-ui, "Segoe UI", Roboto, sans-serif;
  --codeFont:
    "LXGW WenKai Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
}

字体族名以 webfont 包为准:正文 LXGW WenKai(400/700),代码 LXGW WenKai Mono。另有 LXGW WenKai Screen(屏幕优化版,独立包)。

5. 步骤三:修改 quartz.config.yaml

需要改三处:

theme:
  fontOrigin: local # ① 核心系统不再注入 Google Fonts 链接
  typography:
    header: Noto Sans SC # ② 见下方说明
    body: Noto Sans SC
    code: JetBrains Mono
- source: "@quartz-community/quartz-fonts"
  enabled: true
  options:
    fontOrigin: local # ③ 插件也不再注入它自带的 Google 字体
    title: "LXGW WenKai"
    header: "LXGW WenKai"
    body: "LXGW WenKai"
    code: "LXGW WenKai Mono"

② 为什么 theme.typography 保留 Noto Sans SC 而不是改成 LXGW WenKai?
og-image 插件渲染社交分享图(OG 图)时,会按 theme.typography 去 Google Fonts 抓取 TTF 嵌入图片。改成 LXGW WenKai 后:

  • GitHub Actions(云端,网络正常)→ 返回 400 → 优雅降级(警告 + 用回退字体),构建仍成功;
  • 本地网络不稳时 → ECONNRESET构建直接失败
    而页面显示字体由第 4 步的 :root 覆盖决定,与 typography 无关,所以保留 Noto Sans SC 最稳妥:OG 图正常、页面仍显示霞鹜文楷。

6. 步骤四:本地构建验证

npx quartz build
npx quartz build --serve   # 预览 http://localhost:8080

验证要点:

  1. HTML 头部:有 jsDelivr 字体链接,且不再有 fonts.googleapis.com 链接;
  2. CSS 变量:构建产物(index-*.css)中 --bodyFont 等值为 "LXGW WenKai",且出现在 Noto Sans SC 定义之后;
  3. 浏览器实测:正文/标题计算样式为 "LXGW WenKai"document.fonts.check('16px "LXGW WenKai"') 返回 true

7. 步骤五:提交发布

git add quartz.config.yaml quartz/components/Head.tsx quartz/styles/custom.scss
git commit -m "feat(fonts): 站点字体切换为霞鹜文楷(LXGW WenKai,CDN 方式)"
git push origin v5          # 受 ruleset 保护,需管理员/PR

然后到 GitHub Actions 页面手动 Run workflow 触发 deploy.yml 发布到 gh-pages

说明:站点访问者加载字体走 jsDelivr CDN,与你的本地网络/代理是否开启完全无关;发布流水线也在 GitHub 云端执行。唯一可能用到本地网络的是”本地构建”(见下节)。

8. 常见问题

8.1 本地构建报 ECONNRESET(连接被重置)

og-image 插件本地构建时要连 fonts.googleapis.com 抓 Noto Sans SC 的 TTF。网络抖动(或代理未开)时可能 ECONNRESET

  • 字体文件会缓存到 quartz/.quartz-cache/fonts/(gitignored),命中缓存后本地构建不再联网
  • 若清了缓存或换了 typography,重试或确保能连 Google Fonts 即可;
  • GitHub Actions 在云端执行,有稳定网络,发布不受影响

8.2 字体部分子集显示 unloaded

webfont 包把字体按 unicode-range 切成约 120 个子集,浏览器只下载当前页面用到的子集。DevTools 里看到大量 status=unloaded正常的。

8.3 想换回 Google Fonts 上的字体

改回 theme.fontOrigin: googleFontstypography 填 Google Fonts 上的字体名,并移除 Head.tsx 里新增的 <link>custom.scss 的覆盖块即可。

9. 拓展:自托管方案(可选)

若不想依赖 CDN,可把字体文件放进 quartz/static/fonts/(该目录会原样拷贝到站点根目录),步骤为:

  1. lxgw-wenkai-webfont 包批量下载 files/lxgwwenkai-{regular,bold}-subset-*.woff2(约 238 个,5–6 MB);
  2. 把 CSS 里相对路径 ./files/ 改写成 /fonts/
  3. custom.scss@import url("/fonts/lxgwwenkai-regular.css") 或直接引用,并同样覆盖 :root 字体变量。

自托管后页面字体完全由 GitHub Pages 提供,无任何第三方依赖。