VitePress 博客 Yohaku 风格重构:从 Skills 设计契约到 960px 长文版式
一次围绕留白、排版、文章阅读体验与可维护性的系统性改造
这次改造最终落在两个层面:仓库有了用于沉淀 SKILL.md 和设计知识的 skills/ 目录;博客则从原有的 VitePress 视觉样式,迁移为一套以留白、纸张感、克制色彩和长文阅读为核心的 Yohaku 风格主题。
它不是一次简单的“换颜色”。改动覆盖了设计令牌、字体职责、首页信息层级、文章元数据、阅读时间、正文宽度、左右导航、归档列表、代码块、深色模式和移动端布局。文章详情页还参考了 Yohaku Demo Post 的内容节奏,并使用仓库内 skills/design-system/ 的设计契约约束最终实现。
最终目标只有一个:让界面退到内容之后,让文章成为页面里最重要的东西。
一、先建立可复用的 Skills 入口
仓库根目录新增了 skills/,用于放置可以被人和 AI 同时阅读的技能说明、设计规范、参考资料与检查脚本。
当前的 skills/design-system/ 已经不只是一个说明文件,而是一套相对完整的 Yohaku 设计资产:
SKILL.md:描述适用场景、工作流程和必须遵守的约束;CHEATSHEET.md:提供颜色、排版、组件和常见组合的速查表;references/:详细说明令牌、字体、组件和反模式;src/tokens.css:保存设计系统的静态设计令牌;templates/与showcase/:提供可直接观察和复用的页面样例;scripts/check.ts:检查禁用色阶、硬编码字体和令牌漂移。
这让“Yohaku 风格”不再依赖模糊的视觉印象,而是变成一份可以执行的设计合同。博客主题中的颜色、字体、阴影和组件状态,都可以追溯到这份合同。
二、Yohaku 设计语言如何落到博客里
Yohaku 的核心不是日式装饰,而是做减法。设计系统用一句话概括就是:
一种主色,三档中性层级,剩下都是留白。
1. 纸张、暖灰与梅红
主题在 docs/.vitepress/theme/styles/vars.scss 中建立了一套新的语义令牌:
| 角色 | 令牌或颜色 | 用途 |
|---|---|---|
| 纸张背景 | #fefefb | 页面主背景,避免纯白带来的刺眼感 |
| 表面层 | neutral-1 至 neutral-4 | 卡片、代码块、悬停和弱分区 |
| 边界与辅助信息 | neutral-5 至 neutral-7 | 分割线、图标、日期、说明文字 |
| 正文与标题 | neutral-8 至 neutral-10 | 正文、强调文字和最高层级标题 |
| 主色 | #c56473 | 梅红,用于焦点、品牌标记和引用线 |
| 深色主色 | #e095a4 | 深色模式下提高可读性的浅梅红 |
正文默认使用 neutral-9,标题使用 neutral-10,辅助信息使用 neutral-7。neutral-5 只承担边框或弱图标职责,不拿来承载常规文字。
主色也被严格限制在较小的视觉面积中。它出现在首页圆点、活动导航线、按钮、文章分类、二级标题短线、链接下划线和引用块左边框上,而不会铺满大块背景。这样可以保留识别度,又不会破坏页面的安静感。
浅色模式使用略带暖意的中性色阶;深色模式则切换为更纯的灰阶,并只通过纸张背景保留温度。原因是低亮度下的暖灰很容易看起来偏橄榄色,反而会让界面显脏。
2. 三种字体承担三种职责
主题把字体拆分为清晰的三层:
- 无衬线字体负责导航、按钮和功能性界面;
Noto Serif SC等衬线字体负责标题与正文阅读;- 等宽字体负责日期、眉题、阅读时间、代码和统计信息。
中文标题没有使用过重的粗体,而是以 400 或 500 的字重、较紧的字距和更充足的行高建立层级。这比单纯放大、加粗更符合 Yohaku 的克制感。
3. 阴影退场,边界与留白接管层级
旧样式中的强阴影和装饰性代码块外壳被移除。新的层级主要依赖:
- 1px 的低对比度边框;
- 不同中性色表面;
- 纵向留白;
- 字体、字号与字距;
- 极轻的图片阴影。
这种做法让首页、列表和正文在视觉上属于同一个系统,也减少了“通用 SaaS 模板感”。
三、首页从组件堆叠变成编辑式版面
首页的主要实现集中在 VPHome.vue、HomePostsPreview.vue 和 PostCard.vue。
原来的 HomePreview.vue 被删除,docs/index.md 也只保留首页布局声明。首页展示逻辑全部回到 Vue 组件中,避免在 Markdown、默认主题配置和自定义组件之间重复维护。
1. 新的首页首屏
首屏采用左右不对称布局:
- 左侧是站点眉题、主标题、说明文字和两个行动入口;
- 右侧是一张较窄的题记卡片;
- 两部分之间依靠 80px 的间距和底部分割线建立节奏;
- 主标题使用衬线字体,强调“在日常与代码之间,留一页纸给时间”;
- 页面宽度控制在 960px,避免超宽屏上信息过度分散。
右侧题记没有使用卡片阴影,只保留顶部细线、编号、短句和一条梅红色短线,让它更像纸页边缘的旁注。
2. 最近文章列表
首页最多展示 10 篇文章,并按年份倒序取出最新内容。列表会根据当前年份是否已经完整展示,动态决定“继续阅读”的目标年份和提示文案。
桌面端文章卡片采用三列:
日期 112px | 标题与摘要 1fr | 箭头 24px移动端则把日期移动到标题上方,隐藏不必要的横向结构。悬停时只出现非常轻的表面变化,箭头向右移动 4px,主色只用于交互反馈。
四、文章详情页成为真正的长文阅读页
文章页是本次改造最集中的部分。它先参考 Yohaku Demo Post 建立基本结构,随后又经过几轮针对阅读空间的调整:
- 移除左侧目录结构;
- 移除右侧
CONTENTS标题导航模块; - 扩大正文区域;
- 正文字号整体增加约 2px;
- 把“容器最大宽度 960px”修正为“文字内容净宽 960px”。
1. 只对真正的文章详情页启用阅读模式
新增的 docs/.vitepress/utils/page.ts 用路径判断页面类型:
export const isPostDetail = (relativePath: string) =>
relativePath.startsWith("posts/") &&
relativePath.endsWith(".md") &&
!isPostIndex(relativePath);这条规则非常重要。它让 163 篇文章详情页进入 Yohaku 阅读模式,但不会误伤 11 个年份或分类索引页。索引页仍然保留原有导航能力,详情页则专注于阅读。
2. 在构建阶段补齐阅读数据
docs/.vitepress/config.ts 新增 transformPageData。VitePress 在构建页面时读取 Markdown 源文件,去除 Frontmatter、代码块、HTML 标签和 Markdown 符号,然后分别统计中文字符与拉丁单词:
const minutes = Math.max(
1,
Math.ceil(chineseCharacters / 400 + latinWords / 200),
);中文按每分钟约 400 字、英文按每分钟约 200 词估算。最终得到的 wordCount 和 readingTime 被写回页面 Frontmatter,交给文章头部和尾部展示。
同一阶段还会为文章详情页自动设置:
sidebar: false;
aside: false;
outline: false;
pageClass: "yohaku-post-page";因此左侧 Sidebar、右侧 Outline 和窄屏下的目录下拉都会一起关闭,不需要在 163 篇旧文章中逐个添加配置。
3. 文章头部与尾部
ArticleHeader.vue 重新组织了文章开头的信息层级:
- 分类、日期和预计阅读时间位于最上方;
- 主标题桌面端为 40px,移动端为 36px;
- 副标题为 18px;
- 作者区域包含头像占位、作者名、日期与站点标识;
- 有封面图时继续支持图片和来源说明。
ArticleFooter.vue 是新增组件,用于在正文结束后展示标签、字数和预计阅读时间。它与 VitePress 原有的上一篇、下一篇导航共同组成文章收尾。
4. 正文字号与阅读节奏
最终文章正文的排版参数是:
| 元素 | 桌面端 | 移动端 |
|---|---|---|
| 正文 | 17.5px / 1.8 | 17px / 1.78 |
| 一级标题 | 40px | 36px |
| 副标题 | 18px | 18px |
| 二级标题 | 22px | 22px |
| 三级标题 | 18px | 18px |
正文首段增加了首字下沉,二级标题前增加一条 14px 的梅红短线;段落、引用、列表和图片的上下间距也重新收紧,使页面在大字号下仍然保持连续,不会显得松散。
5. 960px 指的是正文净宽
最后一次布局调整解决了一个容易混淆的问题:max-width: 960px 如果设置在带有左右 padding 的外层容器上,真正留给文字的宽度会小于 960px。
现在桌面端采用两层宽度:
.VPDoc.is-post-detail .container {
max-width: 1024px;
}
.VPDoc.is-post-detail .content {
box-sizing: border-box;
max-width: 1024px;
padding: 0 32px 128px;
}
.VPDoc.is-post-detail .content-container {
width: 100%;
max-width: 960px;
}尺寸关系为:
外层内容区域 1024px
- 左侧安全留白 32px
- 右侧安全留白 32px
= 正文文字净宽 960px也就是说,最终测量中的 .content-container 和 .vp-doc 都是 960px,960px 不包含左右 Padding。安全留白由外层 1024px 容器承担。
在小屏幕上不会强制保留 960px,而是继续使用视口内边距和 width: 100%,因此不会产生横向滚动。
五、归档与年份索引同步统一
如果只改文章详情页,用户从首页进入归档时仍然会感到像到了另一个站点。因此 Archives.vue 和 YearIndex.vue 也同步迁移到 Yohaku 语言。
文章归档
归档页按照年份分组:
- 年份在桌面端保持粘性定位;
- 每篇文章显示月日、标题和箭头;
- 行之间使用轻边框,而不是独立卡片;
- 页面头部展示文章总数和浏览说明。
年份索引
年份页使用 COLLECTION · YEAR 作为眉题,展示标题、说明和文章数量。列表中的日期、标题和箭头沿用首页文章卡片的排版逻辑,同时保留上一年、下一年的导航。
这样首页、总归档、年份索引和文章详情形成了一条连续的阅读路径。
六、代码块也回到“内容优先”
代码高亮主题从单一的 nord 改为:
theme: {
light: "github-light",
dark: "github-dark",
}code.scss 同时进行了简化:
- 移除强阴影和类似 macOS 交通灯的装饰;
- 隐藏全屏装饰按钮;
- 使用 Yohaku 边框、圆角和表面色;
- 保留语言标签、行号和高亮行;
- 行内代码使用轻背景与 1px 边框;
- 深浅模式自动使用对应的 Shiki 配色。
代码仍然醒目,但不会比文章正文更抢眼。
七、深色模式与响应式不是附加项
这次主题从设计令牌层就同时定义了浅色和深色,而不是在页面完成后再补一层颜色覆盖。
深色模式下:
- 背景切换为
#181715; - 中性色阶改为纯灰反转;
- 主色提高亮度;
- 导航背景保留半透明与轻微模糊;
- 代码块、分割线和图片阴影使用各自的深色令牌。
响应式方面则重点检查了首页双栏、文章卡片、归档年份、文章头部和 960px 阅读容器。桌面端扩大阅读空间,移动端重新排列信息,而不是简单地按比例缩小。
八、改动文件与职责
主题改造涉及 19 个已有文件的调整,并新增了 3 个主题支持文件、删除了 1 个不再使用的首页组件。
| 范围 | 主要文件 |
|---|---|
| 设计令牌 | styles/vars.scss |
| 全局 Yohaku 规则 | styles/yohaku.scss、styles/index.scss |
| 导航与文档样式 | styles/layouts/nav.scss、styles/layouts/content.scss |
| 代码块 | styles/components/code.scss |
| 页面分类与构建数据 | utils/page.ts、config.ts |
| 文章结构 | Layout.vue、VPDoc.vue、ArticleHeader.vue、ArticleFooter.vue |
| 首页 | VPHome.vue、HomePostsPreview.vue、PostCard.vue |
| 归档 | Archives.vue、YearIndex.vue |
| 文章数据 | posts.data.ts |
| Skills 设计契约 | skills/design-system/ |
实现全部建立在现有 Vue、VitePress 和 Sass 能力之上,没有为了视觉改造增加新的运行时依赖。
九、验证结果
完成样式与布局调整后,执行了完整的生产构建:
npm run docs:build验证范围包括:
- 163 篇文章详情页全部进入无左侧栏、无右侧目录的阅读模式;
- 11 个年份或分类索引页继续保留正常导航;
- 桌面端正文测量结果为 960px,不包含左右各 32px 的安全留白;
- 移动端正文没有横向溢出;
- 首页、归档、年份页和文章页均支持浅色与深色模式;
- 新增阅读时间、字数、标签与文章导航可以正常生成;
- VitePress 生产构建通过。
十、这次重构留下的维护原则
这次改造最重要的产物不是某个页面,而是一套后续可以继续遵守的规则:
- 先改设计令牌,再改局部组件;
- 让字体角色表达信息层级,不依赖大面积颜色;
- 主色只负责焦点,不负责填满页面;
- 用边框和留白建立层级,避免硬阴影;
- 文章详情与索引页面分开判断,避免全局样式误伤;
- 宽度需求必须明确是外层宽度、内容盒宽度,还是文字净宽;
- 每次版式调整都同时验证桌面端、移动端和深色模式;
- 让
skills/design-system/成为设计决策的来源,而不是把规则散落在不同组件里。
Yohaku 的“余白”并不是空,而是主动为文字让出空间。经过这次重构,首页负责邀请,列表负责引导,文章页负责安静地承载内容;设计本身则退到背景中,只在需要的时候出现。