Solejay's Blog
Back to Docs

字体使用指南

博客字体系统配置指南,使用仓耳今楷04-W04字体支持中英文混排

概述#

本博客已集成仓耳今楷04-W04字体,提供优秀的中英文显示效果。字体系统采用统一字体策略,确保中英文混排时有最佳的视觉一致性。

字体配置#

字体文件#

  • 仓耳今楷04-W04 (CangErJinKai): 中英文通用字体,优雅的楷体风格
  • 等宽字体: 代码显示专用字体

字体特性#

  • 仓耳今楷04-W04:优雅的楷体风格,支持中英文混排
  • 字体来源:仓耳字库 ↗
  • 支持字体回退,确保在不同系统下都有良好显示
  • 使用 WOFF2 格式,优化加载性能

使用方法#

1. CSS 类方式#

通用字体(中英文混排)#

.text-content {
  font-family: 'CangErJinKai', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif;
}
css

代码字体#

.code-text {
  font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', 'Source Code Pro', 'Menlo', 'Consolas', 'DejaVu Sans Mono', monospace;
}
css

2. UnoCSS 类方式#

字体族类#

<!-- 使用仓耳今楷字体(中英文混排) -->
<div class="font-wenkai">这是中文内容 This is English content</div>

<!-- 使用等宽字体 -->
<div class="font-mono">console.log('Hello World');</div>
html

组合使用#

<!-- 中英文混合内容 -->
<article class="font-wenkai">
  <h1>文章标题 Article Title</h1>
  <p>这是中文段落内容。This is an English paragraph.</p>
  <pre class="font-mono"><code>const message = "Hello 世界";</code></pre>
</article>
html

3. 组件中使用#

Astro 组件#

---
// 在组件中定义字体样式
const fontClass = 'font-wenkai'
---

<div class={fontClass}>
  <h2>组件标题 Component Title</h2>
  <p>组件内容使用仓耳今楷字体显示,支持中英文混排。</p>
</div>
astro

代码块字体#

---
// 代码块使用等宽字体
---

<div class="font-wenkai">
  <p>正文使用仓耳今楷字体</p>
  <pre class="font-mono"><code>// 代码使用等宽字体
const greeting = "Hello 世界";
console.log(greeting);</code></pre>
</div>
astro

性能优化#

静态字体分包#

页面使用 public/fonts/jinkai/ 下的 WOFF2 分包。app.css 在构建时合并 fonts.generated.css,浏览器根据 unicode-range 请求当前页面需要的分包。 不再预加载完整字体,也不通过 JavaScript 延迟切换字体。

字符分组固定保存在 scripts/font-subsets.json,参考 tw93 的分组 ↗,记录了来源和快照哈希。 这里只参考字符范围,输出字形全部来自本地仓耳今楷 04 W04。 原字体中未被这些分组覆盖的字符,按码点排序,每 188 个字符生成一个补充包。 生成过程不访问 tw93 网站,普通新增文章无需重新分包。

显示与字重#

使用 font-display: swap:下载期间显示后备字体,成功后使用今楷。 慢网下仍可能发生字体替换。后备字体优先 STKaiti、KaiTi,再使用系统黑体。 原字体是固定字重 400;标题的较粗字重由浏览器合成,并非可变字体。

生成与缓存#

安装 uv 后,在仓库根目录运行:

npm run fonts:generate
uv run --with 'fonttools[woff]==4.60.2' python scripts/test_subset_font.py
npm run build
bash

subset_font.py 固定 fontTools/Brotli 版本,读取 public/fonts/cang-er-jin-kai.woff2,同时生成字体、CSS 和体积/覆盖清单 public/fonts/jinkai/manifest.json。生成结果需要随代码提交。 脚本验证声明字符均存在、CSS 范围不重叠、完整覆盖原字体,失败时不发布新产物。 为支持双向排版,字体文件可附带镜像标点字形,但不扩大该包的 CSS 字符范围。 旧哈希文件保留,避免缓存的旧 CSS 引用失效;需清理时先确认旧页面缓存已经过期。

分包文件名包含内容哈希。public/_headers 为 /fonts/jinkai/*.woff2 配置一年不可变浏览器缓存, 不覆盖未带哈希的 manifest.json。此文件由 Cloudflare Pages 处理;GitHub Pages 不应用这项规则。 部署后仍需检查线上响应头是否生效,参考 Cloudflare Pages 文档 ↗。 原始整包作为生成源保留,页面不引用它。

最佳实践#

1. 字体选择原则#

  • 中英文混排内容: 使用 font-wenkai 类(默认字体)
  • 代码内容: 使用 font-mono 类
  • 统一体验: 仓耳今楷字体支持中英文,无需切换字体

2. 响应式字体#

/* 在不同屏幕尺寸下调整字体大小 */
.text-content {
  font-size: 1rem;
}

@media (min-width: 768px) {
  .text-content {
    font-size: 1.125rem;
  }
}

@media (min-width: 1024px) {
  .text-content {
    font-size: 1.25rem;
  }
}
css

3. 字体权重#

/* 标题使用较重的字重 */
h1, h2, h3 {
  font-weight: 600;
}

/* 正文使用正常字重 */
p, div {
  font-weight: 400;
}
css

故障排除#

1. 字体不显示#

  • 检查 public/fonts/jinkai/ 中生成的文件是否完整、请求是否返回 200
  • 确认 CSS 中的字体路径是否正确
  • 检查浏览器开发者工具中的网络请求
  • 确认字体文件格式为 WOFF2

2. 字体加载缓慢#

  • 检查是否只请求所需分包,是否仍存在整包字体请求
  • 检查网络连接和服务器响应时间
  • 考虑使用 CDN 加速字体加载
  • 确认使用了 font-display: swap 策略

3. 字体回退问题#

  • 确认字体回退链配置正确(STKaiti → KaiTi → PingFang SC → Hiragino Sans GB → Microsoft YaHei)
  • 测试在不同系统环境下的显示效果
  • 检查字体文件的兼容性

扩展和自定义#

1. 添加新字体#

  1. 将字体文件(推荐 WOFF2 格式)放入 public/fonts/ 目录
  2. 在 src/assets/styles/app.css 中添加 @font-face 声明
  3. 在 uno.config.ts 中添加字体族配置
  4. 根据实际首屏测量结果决定是否预加载,避免预加载全部分包
  5. 更新字体回退策略

2. 调整现有分包#

修改固定字符分组清单后运行 npm run fonts:generate。不要手动编辑生成的 CSS, 也不要只保留当前文章使用的字符,以免后续文章出现生僻字时失去字体覆盖。

3. 配置入口#

@import './fonts.generated.css';

html, body {
  font-family: 'CangErJinKai', 'STKaiti', 'KaiTi', 'PingFang SC',
               'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
}
css

参考资源#