文章

博客"墨水经典"精修与全站重做纪实

博客"墨水经典"精修与全站重做纪实

这篇文章记录了基于 jekyll-theme-chirpy 7.5 二次开发的个人博客全站改造过程。以”加强而非推翻”为基调,保留杂志风骨架,补强对比度、加入 Hero/作品集网格/三栏页脚,引入克制的滚动揭示与悬停反馈,统一强调色,并修复多个 chirpy 主题与 Liquid 模板的隐性 bug。

一、项目概述

这个博客(xizu233.github.io)基于 jekyll-theme-chirpy 7.5(gem 形式)二次开发,原 UI 已有”墨水经典”杂志风骨架:纯墨黑 #0a0a0b + 暖米白 #f1efea + 衬线/无衬线/等宽三字族。但存在 11 处对比度、响应式、信息架构与视觉层次问题。

本次工作的核心思路是保留杂志骨架,补强薄弱环节

  • 修复对比度问题
  • 加入 Hero 区域、作品集网格、三栏页脚
  • 引入克制的滚动揭示与悬停反馈
  • 统一强调色(墨蓝/米黄)
  • 修复 chirpy 主题与 Liquid 模板的隐性 bug

工作时间:2026-05-01 ~ 2026-05-02
最终 commit:b4b4c8b
GitHub Actions 构建成功。


二、设计决策

在项目启动时,Claude 提供了四种重做方案:

方案描述选择结果
墨水经典精修保留杂志骨架,局部优化选中
推翻重写 Tufte完全不同的学术风格❌ 排除
仅改首页最小改动❌ 排除
强动效方案视差、3D、复杂 transition❌ 排除

最终选择:墨水经典精修 + 全站重做 + 保留 light/dark 双模式 + 中度动效

排除强动效的原因是保持阅读体验优先,排除推翻重写的原因是原有骨架已经符合个人审美偏好。


三、关键架构决策

决策选择原因
主题覆盖策略整体覆盖 chirpy 7.5 的 home/sidebar/footer/topbar/post 五个 layout/includeJekyll 不支持 partial override;这五个是杂志风改造主战场
文章末尾增强通过 chirpy tail_includes 插槽追加不动模板正文,便于未来主题升级
自定义 JS 注入通过 layout frontmatter 的 script_includes 注入复用 chirpy hook,不碰 _includes/js-selector.html
作品集数据驱动_data/projects.yml 抽离结构化数据 + _layouts/projects.html 渲染后续维护只改 yml
Hero 内容front matter 静态 + Liquid 取最新一篇不增加 _config.yml 复杂度
强调色墨蓝 #1f3a5f(light)+ 米黄 #d4b86a(dark)与墨水风格协调,仅用于 link-hover / TOC active / 主按钮
暗色基调#0a0a0b 调到 #16161a,paper 暗对应物 #1f1f24减少纯黑刺眼,仍保持深沉
动效层Intersection Observer + CSS keyframes,全部带 prefers-reduced-motion: reduce 守卫中度动效,可达性兜底

四、技术栈

技术
静态生成Jekyll 4.4.1
主题jekyll-theme-chirpy 7.5.0(gem)
样式SCSS(覆盖 chirpy 变量)
模板Liquid
数据YAML(_data/
脚本Vanilla JS + Intersection Observer
部署GitHub Pages(Actions 构建)
字体 CDNfonts.loli.net
验收工具Playwright(本地 4000 端口预览)
本地构建WSL2 + Ruby/Bundler(--force_polling

不引入新 npm/gem 依赖,保持依赖简洁。


五、实施记录

整个改造分为 8 个 commit,按依赖顺序推进:

Commit 1 · fe9ee5f style(theme): 强化墨水经典对比度与中文排版

改动文件_sass/custom/_colors.scss_sass/custom/_typography.scss

要点

  • 新增 --ink-accent 强调色变量(light=墨蓝、dark=米黄)
  • --ink-faint 从 0.25 提到 0.4(修复链接下划线过淡)
  • 暗色 --main-bg#0a0a0b#16161a--card-bg#ffffff#fbfaf6
  • 元数据 text-transform: uppercase 限定到 :lang(en)(修复中文场景错位)
  • 新增 1024px、1280px 断点
  • TOC active 加 transform: translateX 滑入动画

Commit 2 · 831c0be style(theme): 新增中度动效层

新增文件_sass/custom/_animations.scss_includes/scroll-reveal.html_includes/toc-highlight.html

要点

  • 滚动揭示(fade-in + slide-up 6px)
  • 链接下划线展开
  • 卡片左侧 0 → 3px 竖线悬停
  • TOC active 滑入
  • prefers-reduced-motion: reduce 守卫所有动效

Commit 3 · a6c3a94 style(theme): Hero + 杂志风侧栏顶栏页脚

新增文件_sass/custom/_hero.scss_includes/hero.html_includes/post-tail-magazine.html,整体覆盖 _includes/sidebar.html_includes/topbar.html_includes/footer.html

要点

  • 首页 Hero:ISSUE 号 + 大字号衬线主标题 + 副标题 + 关键词标签 + LATEST 卡片
  • 侧栏插入 “Issue No.{posts.size} — {site.time}” 期刊号
  • 顶栏 #topbar-title 旁加副标题”a quiet journal”
  • 页脚改为三栏 grid:站点简介+版权 / 近期分类 / 联系方式

Commit 4 · bd5cd36 feat(projects): 作品集数据化与响应式网格

新增文件_data/projects.yml_layouts/projects.html_sass/custom/_projects-grid.scss

要点

  • 2 列(≥768)/ 3 列(≥1280)卡片网格
  • 含技术栈标签、外链按钮、悬停升起 1px

Commit 5 · 943f3a4 fix(theme): 修复 Liquid 渲染与 light 模式色变量优先级

这是最重要的修复 commit,解决了 4 个 bug(详见第六节)。

Commit 6 · e0d0041 chore: gitignore 加入本地预览/plan/截图目录

Commit 7 · b4b4c8b fix(about): title 改用英文 key 触发 chirpy locale 翻译


六、修复记录:5 个 bug

Bug 1 · /projects/ 页 document.title 为空(”| Wenchen”)

根因:chirpy _includes/head.htmlpage.title | downcasesite.data.locales[lang].tabs[tab_key] 的 lookup key。中文 title "项目" downcase 后查 zh-CN.yml.tabs 字典 miss,title 退化为空。

修复

  1. 新建本地 _data/locales/zh-CN.yml 全文覆盖 chirpy vendor 内容
  2. tabs 节追加 projects: 项目
  3. _tabs/projects.md 的 title 改为英文 key projects

关键发现:Jekyll 的 _data 是文件级 override(同名 yml 完全替换 theme 提供的版本,不合并),所以必须把 chirpy 原文件全部抄过来再加自定义键。

Bug 2 · light 模式 --main-bg 仍是 white 而非 #f1efea

根因:chirpy _sass/base/_base.scss:12-33@media (prefers-color-scheme: light) { html[data-mode='light'] { ... } } 选择器声明 light 变量,特异性高于纯 :root。原来在 _colors.scss:root 覆盖,被 chirpy 媒体查询里的 html[...] 选择器盖过。

修复:完全重写 _sass/custom/_colors.scss,使用与 chirpy 同选择器特异性的覆盖策略:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
:root {
  --ink: #0a0a0b;
  --paper: #f1efea;
  --paper-tint: #e8e5de;
  --ink-accent-light: #1f3a5f;
  --ink-accent-dark: #d4b86a;
}

/* light 覆盖:与 chirpy 同选择器特异性 */
html:not([data-mode]),
html[data-mode='light'] {
  --main-bg: var(--paper);
  --card-bg: #fbfaf6;
  --sidebar-bg: var(--paper-tint);
  --text-color: var(--ink);
}

html[data-mode='dark'] {
  --main-bg: #16161a;
}

凭借 SCSS import 顺序在 chirpy 之后,相同特异性下后者胜出。

Bug 3 · Liquid slice 在 Hash 上行为不一致

根因site.categories 是 Hash(key=分类名、value=Array),Liquid slice filter 在 Hash 上的行为版本/实现不一致,可能丢键。

修复:改用 sort | for ... limit

1
2
3
4
5
6
7
8
9
10

  ...

  ...

  ...

  ...

Bug 4 · Liquid filter pipeline 顺序导致 slugify 越界

根因'/categories/' | append: cat[0] | slugify 中 slugify 把整串处理,把 /-,URL 错位。

修复:用 capture / assign 抽中间变量:

1
2
<a href="/categories//">

Bug 5 · /about/ 页 title 同样为空

根因:与 Bug 1 同源——title: 关于我tabs[tab_key] lookup miss。

修复_tabs/about.mdtitle: about,触发 zh-CN.yml.tabs.about=关于 翻译。


七、验证矩阵

页面验证项状态
/ 首页 (light)Hero + 卡片 + 三栏页脚通过
/ 首页 (dark)模式切换无跳变通过
/posts/{slug}/TOC 48 锚点 + 相关文章 2 张 + post-nav通过
/projects/作品集网格响应式通过
/categories/5 个分类卡片渲染通过
/tags/21 标签通过
/archives/4 篇文章按年归档通过
/about/关于内容 + 3 章节通过

响应式断点

视口hero-title 字号页脚列数侧栏状态状态
768 x 102436px2 列折叠通过
1024 x 80056px2 列展开通过
1280 x 80068px3 列 (2:1:1)展开 + 右面板通过

八、关键经验

1. Chirpy 主题 lookup 机制

_includes/head.html 在生成 <title> 时按以下顺序:

1
page.title | downcase  →  site.data.locales[lang].tabs[tab_key]  →  page.title

如果 tab_key 在 locale tabs 字典命中就用翻译值,否则回到原 title。中文 title 在 lookup 时下钻到 tabs[中文 key],永远 miss,最终 title 为空

通用模式:自定义 tab 的 title 必须是英文 key,对应翻译写在 _data/locales/{lang}.ymltabs.<key>

2. CSS 变量优先级

chirpy _base.scss@media (prefers-color-scheme) { html[data-mode='X'] { ... } } 而不是纯 :root,特异性是 (0,2,1)。任何在 _colors.scss:root 覆盖(特异性 (0,1,0))都失效。必须用同选择器或更高特异性。

3. Jekyll _data 不合并

_data/locales/zh-CN.yml 在本地存在则完全替换 theme 提供的同名文件。必须把 chirpy vendor 内容全部抄过来,再加自定义键。

4. Liquid filter 链顺序

'/path/' | append: variable | slugify 会把整个 /path/value 一起 slugify,斜杠也被替换。必须先 capture/assign 中间值再 append。

5. WSL2 cross-fs 文件监听

Jekyll 在 WSL2 监听 /mnt/e/ (NTFS cross-fs) 时不收到 inotify 事件,必须加 --force_polling

1
bundle exec jekyll serve --livereload --force_polling

6. 整体覆盖 layout 的维护成本

将 chirpy 5 个文件(home/sidebar/topbar/footer/post)整体覆盖后,未来 chirpy 升级(>= 7.6)需手工合并。已在每个覆盖文件顶部加注释 <!-- Override of jekyll-theme-chirpy@7.5 ... --> 标记基准版本。


九、文件变更清单

新增(15 个文件)

文件作用
_data/projects.yml作品集结构化数据
_data/locales/zh-CN.yml覆盖 chirpy 同名文件,加 projects: 项目
_layouts/projects.html作品集网格渲染
_layouts/home.html整体覆盖 chirpy 7.5 同名
_layouts/post.html整体覆盖(仅 frontmatter)
_includes/hero.html首页 Hero
_includes/sidebar.html整体覆盖 + Issue 期刊号
_includes/topbar.html整体覆盖 + 副标题
_includes/footer.html整体覆盖 + 三栏 grid
_includes/post-tail-magazine.html文章末尾”延伸阅读”
_includes/scroll-reveal.html滚动揭示脚本
_includes/toc-highlight.htmlTOC active 滑入脚本
_sass/custom/_animations.scss动效层
_sass/custom/_hero.scssHero 样式
_sass/custom/_projects-grid.scss作品集网格样式

修改(8 个文件)

文件改动要点
_sass/custom/_colors.scss重写::root 抽象色 + html[data-mode] 覆盖
_sass/custom/_typography.scssuppercase 限 :lang(en),加 1024/1280 断点
_sass/custom/_components.scss卡片悬停左竖线 + reduced-motion 守卫
_sass/custom/_index.scss加 3 个 import
assets/css/jekyll-theme-chirpy.scss同步加 3 个 import
_tabs/projects.mdlayout: projects, title: projects(英文 key)
_tabs/about.mdtitle: about(英文 key)
.gitignore加入 .claude/.playwright-mcp/preview-*.png

十、写在最后

这次改造不只是换了个皮肤,而是把博客从一个”能用的主题”变成了”符合个人审美的阅读空间”。最花时间的不是写样式,而是理解 chirpy 主题的扩展机制、处理 Liquid 模板的隐性行为、以及建立可靠的验证流程。

如果你也在用 Jekyll + Chirpy 搭建博客,希望这篇文章中的踩坑记录能帮你少走一些弯路。


相关链接

本文由作者按照 CC BY 4.0 进行授权