排印即界面:这个博客的设计系统
一个以阅读体验为最高优先级的博客,它的每个设计决策都应该可以被追问「为什么」。这篇文章记录全部答案,同时也是排印系统的全要素测试页。
一个只有文字的网站,排印就是它的全部界面。这篇文章记录这个博客每个设计决策背后的取舍,同时它本身也是排印系统的测试页——你现在看到的每一种元素,都是被刻意设计过的。
字体系统
中英混排是这个博客最基础的约束。技术写作绕不开 Transformer、context window 这类英文术语,所以字体系统必须让两种文字在同一行里和平共处。
方案是三层分工:
- 标题:衬线字体。拉丁字符用 Newsreader(带光学尺寸轴,大字号下笔画对比更优雅),中文回退到思源宋体
- 正文:无衬线。屏幕上的中文长文,无衬线的可读性依然更稳
- 代码:JetBrains Mono,
0和O、1和l永不混淆
正文行高设为 1.95。西文排版的经验值(1.5 上下)对中文来说太挤——汉字是方块字,没有西文的升降部留白,需要更大的行距来制造呼吸感。行宽约束在 40rem,折算成中文大约每行 35 个字,接近传统书籍排版的舒适区间。
色彩:纸、墨与克莱因蓝
底色不是纯白,而是带一丝暖调的纸色 #FAFAF7;文字也不是纯黑,而是 #191A1D 的冷墨色。纯黑配纯白的对比度过高,长时间阅读会累1。
全站只有一个强调色:克莱因蓝。奶油纸底配钴蓝是编辑设计的经典组合,暗色模式下它会亮化成电光蓝 #6C86FF。它出现的地方极少——章节编号、悬停状态、目录高亮、站点印章——正因为少,每次出现才有意义。
高级感的来源不是加法,而是减法之后剩下的东西都经得起追问。
动效原则
动效的职责是确认操作、引导视线,而不是表演。这个博客的动效语言只有四条规则:
- 所有缓动使用自定义贝塞尔曲线,出场
cubic-bezier(0.22, 1, 0.36, 1) - 时长分三档:160ms(悬停反馈)、320ms(状态切换)、640ms(入场)
- 页面跳转用 View Transitions 做标题的共享元素变形,让「点击列表 → 进入文章」有物理连续性
- 尊重
prefers-reduced-motion,没有例外
主题切换用了一个稍微炫技的细节:以按钮为圆心的圆形揭示。实现只需要 View Transitions API 加十行代码:
const transition = document.startViewTransition(applyTheme);
transition.ready.then(() => {
document.documentElement.animate(
{
clipPath: [
`circle(0px at ${x}px ${y}px)`,
`circle(${radius}px at ${x}px ${y}px)`,
],
},
{
duration: 480,
easing: 'cubic-bezier(0.65, 0, 0.35, 1)',
pseudoElement: '::view-transition-new(root)',
}
);
});
技术选型
| 决策 | 选择 | 理由 |
|---|---|---|
| 框架 | Astro 5 | 默认零 JS,内容站的性能上限 |
| 写作 | Markdown | 发布一篇文章 = 提交一个文件 |
| 代码高亮 | Shiki 双主题 | 构建期完成,运行时零开销 |
| 部署 | 纯静态 | 任何 CDN 都能托管 |
整个站点打包后,除了字体之外的 JavaScript 不到 10KB——阅读进度条、目录高亮、主题切换、代码复制,全部算上。
性能数字不是虚荣指标。首屏在 200ms 内渲染完成,这件事本身就是阅读体验的一部分:读者点开链接的那一瞬间,文字已经在那里等着了。
脚注
-
WCAG 对正文对比度的要求是 4.5:1 起,但上限同样值得注意——过高的对比度在暗色模式下尤其刺眼,这也是暗色主题的文字用
#E6E7EA而非纯白的原因。 ↩