从零搭建MkDocs博客
之前用过 Hexo + Fluid 主题写博客,也试过 VitePress,但总感觉不太满意。Hexo 的 Node.js 生态太重,VitePress 更适合写文档而不是博客。最终选择了 MkDocs + Material for MkDocs,搭建过程记录如下。
为什么选 MkDocs Material¶
| 方案 | 优点 | 缺点 |
|---|---|---|
| Hexo + Fluid | 中文社区成熟,主题好看 | Node.js 依赖重,构建慢 |
| VitePress | Vue 生态,构建快 | 文档风格,不适合博客 |
| MkDocs Material | Python 生态,博客功能开箱即用,暗色模式 | 需要 Python 环境 |
Material for MkDocs 支持目录级组织,配合 navigation.indexes 特性可以按分类目录管理文章,结构清晰且无需额外插件。
环境准备¶
安装 uv¶
uv 是 Rust 写的 Python 包管理器,速度极快。
Windows(PowerShell):
Linux / macOS:
验证安装:
初始化项目¶
mkdocs-material会自动安装mkdocs本体和所有依赖mkdocs-literate-nav让导航由各目录的SUMMARY.md文件控制,不用在mkdocs.yml里手动写nav
项目结构¶
my-blog/
├── mkdocs.yml # 主配置文件
├── docs/
│ ├── SUMMARY.md # 顶层导航(tab 级别)
│ ├── index.md # 首页
│ ├── assets/
│ │ ├── images/
│ │ │ └── avatar.png # Logo 和 Favicon
│ │ └── stylesheets/
│ │ └── extra.css # 自定义样式
│ ├── overrides/ # 主题覆盖
│ │ └── partials/
│ │ └── header.html # 自定义 header(社媒链接)
│ ├── python/
│ │ ├── SUMMARY.md # Python 教程导航
│ │ ├── index.md # 分类首页
│ │ ├── conda-to-uv.md # 文章
│ │ └── data-analysis/
│ │ ├── SUMMARY.md # 子分类导航
│ │ ├── index.md
│ │ └── pandas.md
│ ├── agent/
│ │ ├── SUMMARY.md # Agent 导航
│ │ ├── index.md
│ │ └── ...
│ └── tools/
│ ├── SUMMARY.md # 工具导航
│ ├── index.md
│ └── ...
关键设计:
- SUMMARY.md:每个目录一个,控制该目录的导航顺序。新增文章时只需编辑对应目录的
SUMMARY.md - overrides/:覆盖 Material 主题模板,用于自定义 header(如社媒链接)
- index.md:每个分类目录的首页,配合
navigation.indexes特性作为分类落地页
配置文件完全指南¶
所有设置都在 mkdocs.yml 中,下面按功能模块逐项说明。
站点基本信息¶
site_name: 算栗工坊 # 站点名称,显示在浏览器标签页
site_description: LLM、Python 开发及算法等方向的思考与实践 # 站点描述,用于 SEO
site_url: https://suanlilog.com # 站点 URL,用于生成 sitemap
repo_url: https://github.com/suanlilog # 右上角仓库链接
repo_name: suanlilog # 仓库名称显示文字
site_name会出现在浏览器标签页标题中repo_url+repo_name会在导航栏右上角显示 GitHub 图标链接
主题配置¶
theme:
name: material
custom_dir: docs/overrides # 主题覆盖目录
language: zh # 界面语言设为中文
logo: assets/images/avatar.png # 左上角 Logo 图片
favicon: assets/images/avatar.png # 浏览器标签页图标
icon:
repo: fontawesome/brands/github # 仓库链接的图标
custom_dir指向覆盖目录,用于自定义 header 等模板- Logo 和 Favicon:把头像或品牌图标放到
docs/assets/images/目录下,建议用正方形图片,尺寸 100x100 以上
主题色与暗色模式¶
palette:
- scheme: default # 亮色模式
primary: indigo # 主色调
accent: indigo # 强调色
toggle:
icon: material/brightness-7 # 切换按钮图标
name: 切换到暗色模式
- scheme: slate # 暗色模式
primary: indigo
accent: indigo
toggle:
icon: material/brightness-4
name: 切换到亮色模式
- 配置两个
palette项即可实现亮/暗模式切换,右上角会自动出现太阳/月亮图标 primary可选值:red、pink、purple、deep purple、indigo、blue、light blue、cyan、teal、green、light green、lime、yellow、amber、orange、deep orange、brown、grey、blue greyaccent同上,用于按钮、链接等强调元素
字体配置¶
text:可选ubuntu、roboto、open sans、noto sans sc等code:可选ubuntu mono、roboto mono、fira code、source code pro等- 字体通过 Google Fonts 加载,国内访问可能较慢,可自行配置 CDN
导航特性¶
features:
# --- 导航栏 ---
- navigation.tabs # 顶部导航标签页
- navigation.tabs.sticky # 滚动时导航栏固定在顶部
- navigation.sections # 侧边栏分组显示
- navigation.top # 回到顶部按钮
- navigation.indexes # 目录 index.md 作为分类首页
- navigation.instant # SPA 式无刷新页面切换
- navigation.instant.progress # 页面加载顶部进度条
- navigation.footer # 文章页显示上一篇/下一篇
- navigation.tracking # URL 跟踪,侧边栏自动高亮当前章节
# --- 搜索 ---
- search.suggest # 搜索时自动补全
- search.highlight # 搜索结果高亮关键词
- search.share # 搜索可分享链接
# --- 内容 ---
- content.code.copy # 代码块复制按钮
- content.code.annotate # 代码注解功能
- content.tabs.link # 代码标签页同步切换
- content.tooltips # 链接悬浮预览
- toc.follow # 目录跟随滚动自动高亮
常用特性说明:
| 特性 | 效果 |
|---|---|
navigation.tabs |
将 nav 的第一层显示为顶部标签页 |
navigation.tabs.sticky |
标签页滚动时固定,不随页面消失 |
navigation.indexes |
目录的 index.md 作为该分类的落地页 |
navigation.instant |
页面间切换无刷新,类似 SPA 体验 |
navigation.footer |
文章底部自动显示上一篇/下一篇链接 |
content.code.copy |
代码块右上角出现复制按钮 |
toc.follow |
右侧目录跟随页面滚动自动高亮当前标题 |
插件¶
search:提供站内搜索(Material 主题的搜索功能依赖此插件)literate-nav:让每个目录通过SUMMARY.md文件控制导航结构,不用在mkdocs.yml里手写nav
社交链接(导航栏)¶
社媒链接通过主题覆盖(theme override)固定在每页顶部导航栏,而非 footer。这样无论页面多长,访客都能一眼看到。
实现方式:在 docs/overrides/partials/header.html 中覆盖主题的 header 模板,在搜索图标和仓库链接之间注入社媒图标。
{# 在 header.html 的 search 和 repo_url 之间插入 #}
<div class="md-header__social">
<a class="md-icon" href="https://github.com/suanlilog" target="_blank" rel="noopener" title="GitHub">
<svg viewBox="0 0 496 512">...</svg>
</a>
<a class="md-icon" href="https://www.zhihu.com/people/suanligongfang" target="_blank" rel="noopener" title="知乎">
<svg viewBox="0 0 640 512">...</svg>
</a>
<a class="md-icon" href="https://xhslink.com/m/5ZOZtkPwIqW" target="_blank" rel="noopener" title="小红书">
<svg viewBox="0 0 512 512">...</svg>
</a>
</div>
样式写在 docs/assets/stylesheets/extra.css 中:
.md-header__social {
display: flex;
align-items: center;
gap: 0.1rem;
margin-left: 0.2rem;
}
.md-header__social a.md-icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 2rem;
height: 2rem;
color: var(--md-default-fg-color--light);
transition: color 0.2s ease;
opacity: 0.7;
}
.md-header__social a.md-icon:hover {
color: var(--md-primary-fg-color);
opacity: 1;
}
.md-header__social a.md-icon svg {
width: 1rem;
height: 1rem;
fill: currentColor;
}
SVG 图标使用 Font Awesome Free,常用图标参考:
| 平台 | 图标名 | viewBox |
|---|---|---|
| GitHub | github |
0 0 496 512 |
| 知乎 | zhihu |
0 0 640 512 |
| B 站 | bilibili |
0 0 512 512 |
| 微信 | weixin |
0 0 576 512 |
| 邮箱 | envelope |
0 0 512 512 |
Markdown 扩展¶
markdown_extensions:
# --- 基础 ---
- admonition # 告示框(note/warning/tip 等)
- attr_list # 支持为元素添加 HTML 属性
- def_list # 定义列表
- footnotes # 脚注
- tables # 表格
- toc:
permalink: true # 标题旁显示锚点链接
# --- 增强 ---
- pymdownx.details # 可折叠的告示框
- pymdownx.highlight:
anchor_linenums: true # 代码块带行号
- pymdownx.inlinehilite # 行内代码高亮
- pymdownx.superfences # 增强代码块,支持嵌套
- pymdownx.tabbed:
alternate_style: true # 标签页式代码块
- pymdownx.tasklist:
custom_checkbox: true # 任务列表(复选框)
这些扩展配合 Material 主题可以实现丰富的排版效果,详见下方「写作技巧」章节。
自定义样式¶
在 docs/assets/stylesheets/extra.css 中编写自定义样式,可以覆盖主题默认样式。常用自定义:
/* Logo 圆形裁剪 */
.md-header__button.md-logo img {
border-radius: 50%;
width: 2rem;
height: 2rem;
}
/* 页面淡入动画 */
.md-typeset .md-content__inner {
animation: fadeIn 0.3s ease-in;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
/* 告示框圆角 */
.md-typeset .admonition,
.md-typeset details {
border-radius: 8px;
}
/* 表格圆角 + 表头加粗 */
.md-typeset table:not([class]) {
border-radius: 8px;
overflow: hidden;
}
.md-typeset table:not([class]) th {
background-color: var(--md-primary-fg-color--light);
font-weight: 600;
}
/* 搜索弹窗毛玻璃 */
.md-search__overlay {
backdrop-filter: blur(4px);
}
/* 内容区最大宽度 */
.md-grid {
max-width: 1400px;
}
导航结构¶
用 SUMMARY.md 管理导航¶
使用 mkdocs-literate-nav 插件后,导航不再写在 mkdocs.yml 中,而是由每个目录下的 SUMMARY.md 文件控制。
根目录 docs/SUMMARY.md(控制顶部标签页):
分类目录 docs/python/SUMMARY.md(控制侧边栏):
子分类 docs/python/data-analysis/SUMMARY.md:
规则:
- 目录链接用
目录名/格式(如python/),会自动指向该目录的index.md - 文件链接用
文件名.md格式 - 排序完全由
SUMMARY.md中的顺序决定 - 新增文章只需:1)放
.md文件 2)在对应SUMMARY.md加一行
分类首页模板¶
每个分类目录下的 index.md:
---
title: Python教程
---
# Python教程
- [从conda转uv快速上手](conda-to-uv.md) — uv 是用 Rust 编写的 Python 包管理器
- [Pandas 快速入门](data-analysis/pandas.md) — 数据分析必备
写作技巧¶
文章 Front-matter¶
date用于文章排序和展示tags可选,用于标记关键词- 不需要
categories,分类由目录结构决定
告示框(Admonition)¶
类型包括:note、abstract、info、tip、success、question、warning、failure、danger、bug、example、quote。
加 ??? 变成可折叠:
代码块¶
基础用法:
带标题的代码块:
代码高亮特定行:
- 这行会被高亮
标签页¶
配合 content.tabs.link 特性,切换一个页面的标签页会同步切换所有相同标签页。
任务列表¶
表格¶
脚注¶
常用命令¶
# 本地预览(自动刷新)
uv run mkdocs serve
# 构建静态文件(输出到 site/ 目录)
uv run mkdocs build
# 部署到 GitHub Pages
uv run mkdocs gh-deploy
部署到 GitHub Pages¶
- 在 GitHub 创建仓库(比如
username.github.io) - 在仓库 Settings -> Pages,Source 选择
gh-pages分支 - 本地执行:
git init
git add .
git commit -m "initial commit"
git remote add origin https://github.com/username/username.github.io.git
git push -u origin main
uv run mkdocs gh-deploy
gh-deploy 会自动构建并推送到 gh-pages 分支,几分钟后就能访问了。
完整配置参考¶
以下是本博客使用的完整 mkdocs.yml:
site_name: 算栗工坊
site_description: LLM、Python 开发及算法等方向的思考与实践
site_url: https://suanlilog.com
repo_url: https://github.com/suanlilog
repo_name: suanlilog
theme:
name: material
custom_dir: docs/overrides
language: zh
logo: assets/images/avatar.png
favicon: assets/images/avatar.png
icon:
repo: fontawesome/brands/github
palette:
- scheme: default
primary: indigo
accent: indigo
toggle:
icon: material/brightness-7
name: 切换到暗色模式
- scheme: slate
primary: indigo
accent: indigo
toggle:
icon: material/brightness-4
name: 切换到亮色模式
font:
text: Noto Sans SC
code: Fira Code
features:
- navigation.tabs
- navigation.tabs.sticky
- navigation.sections
- navigation.top
- navigation.indexes
- navigation.instant
- navigation.instant.progress
- navigation.footer
- navigation.tracking
- search.suggest
- search.highlight
- search.share
- content.code.copy
- content.code.annotate
- content.tabs.link
- content.tooltips
- toc.follow
extra_css:
- assets/stylesheets/extra.css
extra: {}
plugins:
- search
- literate-nav
markdown_extensions:
- admonition
- attr_list
- def_list
- footnotes
- tables
- toc:
permalink: true
- pymdownx.details
- pymdownx.highlight:
anchor_linenums: true
- pymdownx.inlinehilite
- pymdownx.superfences
- pymdownx.tabbed:
alternate_style: true
- pymdownx.tasklist:
custom_checkbox: true
踩坑记录¶
VitePress 中文文件名问题¶
之前用 VitePress 时踩的坑:VitePress 对中文文件名支持有问题,构建时会报 Cannot read properties of undefined (reading 'imports')。文章文件名一定要用英文,标题写在 frontmatter 里。
Material 图标语法不渲染¶
Material for MkDocs 的图标语法(如 :material-clock-fast:)需要配置 pymdownx.emoji 扩展才能渲染。如果不想折腾,直接用纯文字或 emoji 就好。
Blog 插件不适合分类博客¶
最初尝试用 MkDocs Material 的 blog 插件,但发现它会自动排除 blog/ 目录下非 posts/ 的 markdown 文件,导致分类页面无法正常工作。
最终方案:放弃 blog 插件,改用目录组织。文章按分类放入对应目录,每个目录一个 index.md 作为分类首页,配合 navigation.indexes 特性实现分类导航。结构更简单,也不需要折腾插件。
首页模板报错¶
不要在 frontmatter 里写 template: home.html,Material for MkDocs 没有这个模板。
总结¶
MkDocs Material 搭建博客非常省心,Python 生态 + 目录级组织,暗色模式、代码高亮、搜索、分类导航全都有。不需要 blog 插件,按目录分类 + navigation.indexes + mkdocs-literate-nav 就能实现清晰的分类导航。相比 Hexo 少了很多折腾,相比 VitePress 更适合写博客。
如果你也在找一个简洁好用的博客方案,推荐试试。