Lumin Blog 专题功能:系列文章聚合与管理
📌 概述
专题(Topic)系统是 Lumin Blog 的一项自定义内容聚合功能,基于 Hugo 的 Taxonomy(分类法)机制实现。与传统的分类/标签不同,专题设计为策划编辑型内容——由博主手动挑选相关文章归入一个专题,形成系列化的阅读体验。
每个专题拥有独立的封面 Banner、简介描述和文章列表页,适合打造「开发日志」「旅行游记」「读书笔记」等系列内容。
本功能完全基于 Hugo 模板系统实现,无需任何第三方插件,所有样式内聚在
main.css中。
🎯 一、功能说明
| 属性 | 说明 |
|---|---|
| 专题页面 | /topics/ — 展示所有专题的卡片网格,带 Hero Banner 和面包屑导航 |
| 专题内页 | /topics/<topic-slug>/ — 展示该专题下的所有文章,带封面 Banner |
| 文章关联 | 在文章 frontmatter 中添加 topics 字段即可归入专题 |
| 统计展示 | Hero Banner 内显示专题总数和聚合文章数 |
| 面包屑 | 标准 .breadcrumb 组件,首页 › 专题 / 首页 › 专题 › 专题名 |
| 响应式 | 桌面端多列卡片网格,平板端自动减少列数,手机端单列 |
| 暗黑模式 | 完整适配 [data-theme="dark"] |
与标签/分类的区别
| 特性 | 分类 | 标签 | 专题 |
|---|---|---|---|
| 粒度 | 粗(最多 2 级) | 细 | 策划级别 |
| 创建方式 | 文章 frontmatter 自动生成 | 文章 frontmatter 自动生成 | 手动创建 _index.md + 手动关联 |
| 页面 | 列表页 | 列表页 + 标签云 | 双页系统(Hub + Detail) |
| 封面 | 无 | 无 | 支持自定义封面图 |
| 简介 | 无 | 无 | 支持描述文字 |
| 导航入口 | 分类列表 | 标签云 | 导航栏「专题」 + 卡片直达 |
🏗️ 二、架构设计
2.1 文件结构
1myblog/
2├── hugo.toml # [taxonomies] 添加 topic = "topics"
3├── content/
4│ └── topics/
5│ ├── _index.md # 专题 Hub 页元数据
6│ └── lumin-blog/
7│ └── _index.md # 单个专题元数据(标题、描述、封面)
8
9themes/hugo-theme-lumin/
10├── layouts/
11│ └── topics/
12│ ├── terms.html # 专题 Hub 页面模板(所有专题的卡片网格)
13│ └── list.html # 单个专题内页模板(文章列表 + 封面 Banner)
14└── assets/
15 └── css/
16 └── main.css # 专题相关样式(L6830 起)
2.2 Hugo 布局解析
Hugo 对 Taxonomy 的布局查找顺序:
| 页面类型 | URL | 渲染模板 |
|---|---|---|
| Taxonomy Hub(全部专题) | /topics/ | layouts/topics/terms.html |
| Taxonomy Term(某个专题) | /topics/lumin-blog/ | layouts/topics/list.html |
| Section(内容目录) | /topics/(备用) | layouts/topics/list.html(已做 .Kind 判断排除) |
关键点:list.html 同时服务于 section 页面和 term 页面,需要在模板顶部区分页面类型(参见踩坑记录)。
2.3 数据流
1文章 frontmatter Hugo Taxonomy 引擎
2topics: ["lumin-blog"] ──────────► 收集所有标记了 topics 的文章
3 按 topic term 分组
4 ┌──────────────────────┐
5 terms.html │ lumin-blog: [p1,p2] │
6 遍历 .Data.Terms │ travel: [p3] │
7 渲染专题卡片网格 │ reading: [p4,p5] │
8 └──────────────────────┘
9 │
10 ▼
11 list.html
12 接收 .Data.Term + .Pages
13 渲染封面 Banner + 文章列表
⚙️ 三、配置
3.1 注册 Taxonomy
在 hugo.toml 的 [taxonomies] 中添加:
1[taxonomies]
2 category = "categories"
3 tag = "tags"
4 topic = "topics" # 新增:专题分类法
Hugo 会自动为 /topics/ 和 /topics/<term>/ 生成页面。
3.2 导航菜单
1[[menu.main]]
2 identifier = "topics"
3 name = "专题"
4 url = "/topics/"
5 weight = 8
🏠 四、专题主页(/topics/)
4.1 Hero Banner
居中渐变紫色 Banner,包含:
- 图标:圆角方形半透明背景,内含书籍 SVG 图标
- 标题:通过
_index.md的title控制(默认「专题」) - 描述:通过
_index.md的description控制 - 统计药丸:两个玻璃态药丸 —
N 个专题+M 篇文章
1.topics-hero {
2 border-radius: 16px;
3 padding: 48px 40px;
4 background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #4a47a3 100%);
5}
4.2 面包屑导航
采用主题标准的 .breadcrumb 组件,位于 Banner 上方:
1首页 › 专题
4.3 专题卡片网格
使用 CSS Grid 响应式布局:
1.topics-grid {
2 display: grid;
3 grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
4 gap: 20px;
5}
每张卡片结构:
1┌─────────────────────────┐
2│ │
3│ 封面图 / 渐变色背景 │ ← topic-card-cover (160px)
4│ [N 篇] │ ← 右下角文章计数徽章
5│ │
6├─────────────────────────┤
7│ 专题标题 │
8│ 简介描述(最多 2 行省略) │ ← topic-card-body
9│ ───────────────────── │
10│ 浏览专题 → │ ← topic-card-footer
11└─────────────────────────┘
动态主题色:每张卡片的渐变遮罩颜色根据文章数量取模选择:
1{{- $colors := slice "#667eea" "#764ba2" "#e74c3c" "#27ae60" "#f39c12" "#2980b9" "#16a085" "#8e44ad" "#d35400" "#2c3e50" -}}
2{{- $colorIdx := mod (len $topic.Pages) (len $colors) -}}
3{{- $accent := index $colors $colorIdx -}}
Hover 效果:translateY(-4px) + 紫色阴影 + 箭头右移 3px。
📖 五、专题内页(/topics/<slug>/)
5.1 封面 Banner
采用背景图 + 渐变遮罩的覆盖层设计:
1.topic-hero {
2 position: relative;
3 border-radius: 16px;
4}
5
6.topic-hero-bg {
7 min-height: 220px;
8 background-size: cover;
9 background-position: center;
10}
11
12.topic-hero-body {
13 position: absolute; /* 覆盖层,不增加高度 */
14 inset: 0;
15 display: flex;
16 flex-direction: column;
17 align-items: center;
18 justify-content: center; /* 内容垂直居中 */
19 color: #fff;
20}
注意:
.topic-hero-body必须使用position: absolute覆盖在.topic-hero-bg上,否则会作为独立块级元素撑开布局。详见踩坑记录。
Banner 内容:
- 书籍图标(48×48 圆角方形,半透明背景)
- 专题标题
- 专题描述
- 文章统计药丸
动态主题色:渐变遮罩颜色基于 .Data.Term 字符串长度取模:
1{{- $accent := index $colors (mod (len .Data.Term) (len $colors)) -}}
5.2 面包屑导航
1首页 › 专题 › 当前专题名
单击「专题」返回专题 Hub 页。
5.3 文章列表
每篇文章为水平卡片布局:
1┌──────────┬──────────────────────────────────┐
2│ │ 2026-05-22 代码 6分钟 2544字 │
3│ 封面缩略图│ 文章标题 │
4│ │ 文章描述文字,最多两行省略... │
5└──────────┴──────────────────────────────────┘
- 桌面端:左侧缩略图 170px 宽,右侧自适应
- 平板端:缩略图缩小到 140px
- 手机端:缩略图缩小到 110px
📝 六、创建与管理专题
6.1 创建专题元数据
在 content/topics/<slug>/_index.md 中创建:
1---
2title: "Lumin Blog 开发日志"
3description: "记录 Lumin Blog 主题从零到一的完整开发过程"
4cover: "/images/default-cover.webp"
5---
| 字段 | 必填 | 说明 |
|---|---|---|
title | 是 | 专题显示名称 |
description | 否 | 专题简介,显示在卡片和 Banner 中 |
cover | 否 | 专题封面图,用于卡片和内页 Banner |
6.2 关联文章到专题
在文章 frontmatter 中添加 topics 字段:
1---
2title: "某篇文章"
3categories:
4 - "code"
5tags:
6 - "Hugo"
7topics:
8 - "lumin-blog" # 文章归入该专题
9description: "文章描述"
10author: "Lumin"
11---
一篇文章可以归属于多个专题:
1topics:
2 - "lumin-blog"
3 - "hugo-tips"
6.3 专题 Hub 元数据
content/topics/_index.md 控制 Hub 页的标题和描述:
1---
2title: "专题"
3description: "精选专题,系统化阅读,深入探索每一个主题"
4---
🎨 七、CSS 样式系统
专题系统共用约 300 行 CSS,分为三个区块:
7.1 Hub 页样式
| 类名 | 作用 |
|---|---|
.topics-hero | Hub 页渐变 Banner |
.topics-hero-content | Banner 内容容器 |
.topics-hero-icon | 书籍图标容器 |
.topics-hero-title | Banner 标题 |
.topics-hero-desc | Banner 描述 |
.topics-hero-stats | 统计药丸容器(flex 水平排列) |
.topics-hero-stat | 单个统计药丸(玻璃态) |
.topics-grid | 专题卡片网格 |
.topic-card | 单张专题卡片 |
7.2 内页样式
| 类名 | 作用 |
|---|---|
.topic-hero | 内页 Banner 容器 |
.topic-hero-bg | 背景图容器(min-height: 220px) |
.topic-hero-gradient | 彩色渐变遮罩(position: absolute; inset: 0) |
.topic-hero-body | 内容覆盖层(position: absolute; inset: 0) |
.topic-hero-meta | 文章统计容器 |
.topic-article-grid | 文章列表容器 |
.topic-article-card | 单篇文章卡片 |
7.3 暗黑模式
1[data-theme="dark"] .topics-hero {
2 background: linear-gradient(135deg, #4a47a3 0%, #5b3a8c 50%, #3a3580 100%);
3}
4[data-theme="dark"] .topic-card {
5 background: rgba(0,0,0,0.15);
6 border-color: rgba(255,255,255,0.06);
7}
8[data-theme="dark"] .topic-article-card {
9 background: rgba(0,0,0,0.15);
10 border-color: rgba(255,255,255,0.06);
11}
📱 八、移动端适配
| 断点 | 变化 |
|---|---|
| ≤768px | Hero padding 减小;标题字号缩小;专题卡片 2 列;封面 Banner 降至 180px |
| ≤480px | 专题卡片 1 列;统计药丸换行显示;文章缩略图缩小到 110px |
⚠️ 九、踩坑记录
9.1 专题卡片链接 404
问题:专题 Hub 页点击卡片跳转到 /lumin-blog/ 而非 /topics/lumin-blog/,导致 404。
原因:terms.html 中卡片链接错误地直接使用了 $topic.Term,丢失了 taxonomy 前缀。
1<!-- ❌ 错误 -->
2<a href="{{- $topic.Term | urlize | relLangURL -}}/">
3
4<!-- ✅ 正确 -->
5<a href="{{- $topic.Page.RelPermalink -}}">
9.2 .Data.Term 空值报错
问题:content/topics/_index.md 作为 section 页面渲染时,.Data.Term 为 nil 导致 len 调用 panic。
原因:list.html 同时服务 section 页面和 term 页面。早期的 {{- if not .Data.Term -}} 守卫在某些 Hugo 版本中对 nil 接口无法正确求值。
修复:改用 .Kind 判断页面类型:
1{{- if ne .Kind "term" -}}
2 <div class="list-page">
3 {{- with .Content }}{{ . }}{{ end -}}
4 </div>
5 {{- return -}}
6{{- end -}}
.Kind 值 | 页面类型 |
|---|---|
"section" | 普通内容目录 |
"taxonomy" | 分类法列表页 |
"term" | 分类法词条页(专题内页) |
9.3 Banner 与文章列表间距过大
问题:专题内页的封面 Banner 和下方文章列表之间有 ~270px 的空白区域。
原因:.topic-hero-body 使用了 position: relative,作为 .topic-hero-bg 的兄弟块级元素渲染在下方,导致 Hero 总高度 = bg 高度 + body 高度 ≈ 448px。
修复:将 .topic-hero-body 改为 position: absolute; inset: 0 覆盖在 bg 上,并添加 flex 居中:
1.topic-hero-body {
2 position: absolute;
3 inset: 0;
4 display: flex;
5 flex-direction: column;
6 align-items: center;
7 justify-content: center;
8}
修复后 Hero 总高度 = min-height: 220px,文章列表通过 margin-top: 25px 紧随其后。
留言评论
期待你的想法评论加载中