前言
个人博客的意义,从来不只是"有个地方写东西"。它是一块自留地——你的域名、你的排版、你的交互——所有细节都由你掌控。选型阶段我选择了 Hugo + Stack 主题,理由是:
- Hugo 构建极快,Markdown 写作体验流畅
- Stack 主题设计克制,信息密度适中,暗色模式原生支持
- 两者都有活跃社区,踩坑成本可控
本文按时间线整理从零搭建到细节美化的全过程,既是自我复盘,也希望能帮到同样折腾 Hugo 的朋友。
基础设施
GitHub Actions 自动部署
博客源码托管在 GitHub,每次推送到 main 分支自动构建并部署到 GitHub Pages。工作流文件位于 .github/workflows/deploy.yml:
| |
几点注意:
fetch-depth: 0确保 CI 环境能读取完整 Git 历史,配合enableGitInfo(后文会提)自动获取文章最后修改时间- Hugo 子模块必须
recursive拉取,否则主题缺失导致构建失败 - 自定义域名
blog.areacloser.top在仓库 Settings → Pages 中配置,configure-pages会自动识别
主题文件覆盖策略
铁律:绝不原位修改主题文件。 所有定制通过同名文件覆盖实现——在项目根目录的 layouts/、assets/、i18n/ 下创建与主题路径一致的文件,Hugo 会自动优先读取。
中文适配
分类/标签页标题翻译
访问 /tags/gallery/ 这样的分类子路由时,页面顶部会显示全大写 “TAGS” 而非中文。问题有两层:
| 层面 | 原因 |
|---|---|
| 模板 | layouts/list.html 中 {{ .Parent.Title }} 返回 Hugo 默认的英文分类名 |
| 样式 | general.scss 中 .section-title { text-transform: uppercase; } 把小写强制转大写 |
修改:
i18n/zh.toml新增:
| |
layouts/list.html覆写模板,将{{ .Parent.Title }}替换为:
| |
逻辑:拼接 i18n key(如 taxonomy.tags)查找中文,找不到则回退到原始标题。
assets/scss/custom.scss取消大写:
| |
页面英文路由
归档(关于)和友链页面原本的路由是 /关于/ 和 /链接/。原因在于 hugo.toml 中 permalinks.page = "/:slug/",而这两个页面的 front matter 没有指定 slug,Hugo 便从中文 title 自动推导。
修改: 在 content/page/about/index.md 和 content/page/links/index.md 的 front matter 中添加:
| |
路由变为 /about/ 和 /links/,标题仍保持中文不变。
交互与动画
所有动画集中在 assets/scss/custom.scss,遵循 0.6s ease 过渡 + scale(1.03) 放大 的统一风格。
主页文章卡片
| |
整卡可点击
默认只有标题和图片可点击跳转。用 ::after 伪元素拉伸标题链接覆盖图片以外的整个卡片区域:
| |
归档页与友链页
归档页改为两栏网格布局,友链页三栏,卡片悬停缩放:
| |
归档的缩放为 1.02 而非 1.03,因为两栏间距较小,放大过多会显得拥挤。
侧边栏互动
搜索框、归档列表、标签云均有悬停缩放:
| |
图片圆角统一
分类页顶部缩略图、归档/友链的卡片右侧图片,统一添加 8px 圆角:
| |
首页欢迎横幅
仅在第一页显示({{ if eq $paginator.PageNumber 1 }}),分页不重复。
layouts/index.html 覆盖主题 home.html,在文章列表前插入:
| |
卡片式风格,悬停同样有缩放效果。文字可在模板中自由更换。
文章内信息增强
作者显示
在文章详情区(日期和阅读时长之间)添加作者信息,仅在 front matter 指定 author 时显示。
覆盖 layouts/_partials/article/components/details.html:
| |
在任意文章的 front matter 中添加一行 author: Xalok 即可生效。
文章尾部信息
覆盖 layouts/_partials/article/components/footer.html,尾部从上到下依次为:
- 标签
- 👁 访问统计(Waline pageview,加载时显示"···“占位)
- ✏ 最后更新于(仅在
.Lastmod ≠ .Date时显示,图标为编辑笔) - © 授权信息
最近修改自动检测
在 hugo.toml 中启用:
| |
Hugo 的 .Lastmod 解析优先级:front matter lastmod 字段 → Git 提交时间 → .Date(回退)。启用后,只要内容文件有新的 Git 提交,Lastmod 就会自动更新,无需手动维护 front matter 中的 lastmod。
Footer 美化
一言引用
通过 一言 API 获取游戏类句子(c=c),显示在分隔线和版权信息之间。新建 layouts/_partials/footer/hitokoto.html:
| |
CSS 中使用 color: var(--body-text-color) 确保亮/暗色主题下文字均可见,出处文字 opacity: 0.6 形成层次。
网站运行时长
在 footer 底部显示自建站以来的运行天数、时、分、秒,每秒刷新。非静态渲染,纯前端 JS 计算。
站点访问统计
通过 Umami 自建实例 API 获取全站 浏览量/访客/访问次数,挂载在 <span id="visit-info"> 上。params.toml 中预设了占位文字:
| |
JS 异步获取数据后替换为实际数值,请求失败时显示零值。
Git 提交时间线
以上功能按以下顺序逐步迭代:
| 提交 | 内容 |
|---|---|
a9418ef | 初始化 Hugo + Stack 主题 |
bf80f7d | GitHub Actions 自动部署 |
8e70b25 | 社交媒体图标与链接 |
c06b5f5 | 中文 i18n、分类标题翻译、section 样式 |
5778bd1 | 卡片悬停动画、归档/友链网格布局 |
bef1714 | 首页欢迎横幅、一言、浏览量、作者显示 |
ad37e9d | 运行时长、图片圆角统一、Waline 浏览量 |
cfab843 | Umami 全站统计 |
7220d06 | enableGitInfo、内容更新 |
ed3bfc5 | 整卡可点击 |
后记
从新建文件夹到一键部署不过是几条命令的事,真正花时间的是那些"不够好"的细节——分类标题为什么是全大写、页面路由为什么是中文、卡片为什么只能点标题。每一次追问和修复,都是让博客更接近心中模样的过程。
如果你也在用 Hugo + Stack,希望这篇文章能帮你少走些弯路。
