Zola 模板开发要点与 Markdown 语法速查
Zola 模板的核心机制(结合 Zola 官方文档 与本站实践),以及参考 daudix.one/content 整理的 Markdown / Shortcode 写法示例。
警告:
zola.toml若启用新功能, 记得在该文档中 更新说明 使用方法
一、Zola 模板:目录与优先级
Zola 的模板引擎是 Tera(语法接近 Jinja2 / Liquid)。站点根目录结构:
.
├── config.toml # 全局配置
├── content/ # Markdown 内容(按 section 组织)
├── templates/ # 站点级模板(优先级高于 theme)
├── static/ # 原样拷贝的静态资源
├── sass/ # 可选,编译为 CSS
└── themes/ametrine/ # 主题(可被 templates/ 同名文件覆盖)覆盖规则:templates/ 下与主题同路径的文件会完全替换主题模板。例如:
{# templates/article.html — 只改文章页,不动 theme #}
{%% extends "ametrine/templates/article.html" %%}
{%% block content %%}
{{ super() }}
{# 追加滚动条、热力图等 #}
{%% endblock %%}原则:不改
themes/内文件,在templates/里 extends + block 扩展。
二、模板类型与 front matter 绑定
| 模板文件 | 用途 | 典型绑定方式 |
|---|---|---|
base.html | 全站骨架(<html>、header、sidebar、footer) | 被其他模板 extends |
section.html | Section 索引页(_index.md) | section 默认模板 |
page.html | 独立 Page | page 默认模板 |
article.html | 单篇文章 | page_template = "article.html" |
article_list.html | 文章列表 + 分页 | template = "article_list.html" |
自定义如 archive.html | 归档页等特殊布局 | _index.md 中 template = "archive.html" |
Section 的 _index.md 示例(参考 daudix 的 blog/_index.md):
+++
title = "效率-工作流"
sort_by = "date"
template = "article_list.html" # 列表页模板
page_template = "article.html" # 该 section 下每篇文章的模板
paginate_by = 10
generate_feeds = true
[extra]
no_header = true # 传给模板,控制是否渲染 h1
+++三、Tera 核心语法
3.1 继承与块(extends / block / super)
{%% extends "ametrine/templates/base.html" %%}
{%% block content %%}
<main>{{ section.content | safe }}</main>
{%% endblock content %%}在子模板中调用父块内容:super() 过滤器(写作 {{ super() }})(本站 article.html 即此模式)。
3.2 引入片段(include / import)
{%% include "partials/heatmap_component.html" %%}
{%% import "macros/macros.html" as macros %%}
{{ macros::translate(key="skip_to_content", default="Skip", language_strings=language_strings) }}3.3 常用变量(构建时注入)
| 变量 | 含义 |
|---|---|
config | zola.toml 全文,含 config.extra.* |
page | 当前页面(title、date、content、permalink、taxonomies…) |
section | 当前 section(pages 列表、title…) |
lang | 当前语言 |
current_url | 当前页面 URL |
3.4 常用函数与过滤器
{# 跨 section 拉取文章 — archive.html 中的用法 #}
{%% set sec = get_section(path="03Share_blog/_index.md") %%}
{%% set posts = sec.pages | sort(attribute="date") | reverse %%}
{# 加载外部数据 #}
{%% set strings = load_data(path="i18n/en.toml") %%}
{# 过滤器链 #}
{{ page.date | date(format="%Y-%m-%d") }}
{{ heat_data | json_encode() | safe }}
{%% for year, posts in all_posts | group_by(attribute="year") %%}3.5 图片处理(build 时)
主题 base.html 中常见写法:
{%% set blurnail = resize_image(path=page.colocated_path ~ banner, width=4, height=2, op="fill", format="webp") %%}page.colocated_path 指向与 index.md 同目录,便于 co-located 资源。
四、Shortcode(短代码)
放在 templates/shortcodes/*.html,Markdown 中写作:
{%% shortcode_name(param="value") %%}
内容
{%% end %%}或自闭合:{%% icon(name="github") %%}
在 Markdown 正文中展示 shortcode 字面量时,用
{%%/%%}转义,避免被 Zola 当作 shortcode 执行。
查找顺序:站点 templates/shortcodes/ → 主题 themes/ametrine/templates/shortcodes/。
五、Markdown 语法示例
以下示例整理自 daudix.one 的常见写法,并标注 ametrine 支持情况。
5.1 Front matter(TOML)
+++
title = "文章标题"
description = "摘要,用于列表卡片与 SEO"
date = 2026-06-22
updated = 2026-06-22
draft = true # 草稿,需 zola build --drafts
[taxonomies]
tags = ["Zola", "Devlog"]
categories = ["Featured"]
[extra]
toc = true # 目录
accent_color = ["hsl(254 44% 55%)", "hsl(290 20% 71%)"] # 浅色/深色强调色
banner = "banner.webp" # 与 index.md 同目录的横幅图
[extra.fediverse]
host = "vmst.io"
user = "username"
id = "113295812044964246" # 启用 Fediverse 评论
+++section级(_index.md)
+++
title = "CMake 4.0 技术细节整理 专栏"
description = "My writings, I suppose."
sort_by = "date"
template = "article_list.html"
page_template = "article.html"
paginate_by = 10
generate_feeds = true
[extra]
scripts = ["analytic/umami.js"] # 启用访客来源统计
no_header = true
+++
page级(index.md)
+++
title = "Mac 本地网络 配置优化方案"
description = "提升网络访问性能,减少硬件性能损耗"
updated = 2026-06-20 # 最新更新时间, 若 section的_index.md 中设置以时间排序,以这个为准
date = 2026-06-20 # 👈 确保这里有规范的日期
[taxonomies]
tags = ["zsh","Mac" ] # 标签
categories = ["Hot"] # 分类
[extra]
accent_color = ["hsl(26.511627 25% 34%)", "hsl(26.75676 31% 53%)"]
+++5.2 内部链接
Zola 专用 @/ 前缀,构建时解析为正确 permalink:
详见 [网站重写 Devlog](@/blog/2023-08-13-site-and-blog-devlog/index.md)
脚注式引用:[为什么叫这个名字?](@/03Share_blog/2025-10-04-Zola-build-deploy-circle/index.md)5.2.0 页间跨页跳转
``TODO` 待补充
5.2.1 页内块跳转
``TODO` 待补充
5.3 标题与目录
## 二级标题 → 自动生成锚点
### 三级标题
[extra] toc = true → 文章顶部自动生成目录5.4 文本样式
**粗体** *斜体* ~~删除线~~ `行内代码`
> 引用块
> 可以多行
上标脚注引用[^1],文末定义脚注内容。
[^1]: [Dependency hell](https://en.wikipedia.org/wiki/Dependency_hell)5.5 术语块(daudix 风格)
**SSG:** Static Site Generator,将 Markdown 转为静态 HTML 的构建工具。
5.6 表格
| 页面 | 旧仓库 | 新仓库 |
| ---- | ------ | ------ |
| Home | pages | website |
| Blog | blog-source | website |5.7 代码块
支持语法高亮(本站 zola.toml 配置 monokai-pro 主题):
TOML 配置示例:
[markdown]
smart_punctuation = true
github_alerts = trueHTML 模板示例(Tera 语法,写作时用 {%% / %%} 转义可在正文中展示字面量):
{%% extends "base.html" %%}
{%% block content %%}{{ page.content | safe }}{%% endblock %%}Shell 命令:
zola build --force
zola serve --drafts5.8 GitHub Alerts(github_alerts = true 时)
> [!NOTE]
> 这是提示框,无需手写 shortcode。
> [!WARNING]
> 警告信息。
> [!TIP]
> 小技巧。等价的 shortcode 写法(ametrine alert.html):
{%% alert(title="Note", icon="info", color="note") %%}
自定义图标与颜色的提示块。
{%% end %%}5.9 图片
普通 Markdown 图片(与 index.md 同目录放 photo.png):
daudix 技巧:URL 锚点控制样式(无需 Kramdown 的 {: .class}):


对应 SCSS 选择器示例:
img[src*="#transparent"] { background: transparent; }
img[src*="#pixels"] { image-rendering: pixelated; }Shortcode 图片(更多参数):
{%% image(url="banner.webp", alt="横幅", full=true, drop_shadow=true) %%}5.10 ASCII / CRT 艺术字
Section 首页与 daudix blog 首页常用的 crt shortcode:
{%% crt(label="ASCII 插画:左侧卡车,中间房屋,右侧火箭") %%}
* *
* _________##
@\\\\\\\\\##
* @@@\\\\\\\\##\
{%% end %%}渲染为 .crt 样式的 <pre>,带 CRT 扫描线效果。
5.11 嵌入媒体
YouTube(隐私增强域名,需 CSP 允许 youtube-nocookie.com):
{%% youtube(id="dQw4w9WgXcQ") %%}
{%% youtube(id="abc123", start=30, autoplay=false) %%}Vimeo / 本地视频 / 音频:
{%% vimeo(id="123456789") %%}
{%% video(url="clip.mp4", controls=true, loop=true, muted=true) %%}
{%% audio(url="podcast.mp3", name="播客片段") %%}5.12 图标
{%% icon(name="github") %%}
{%% icon(name="terminal", inline=true) %%}图标来自 Phosphor SVG,主题 icons/phosphor/ 目录。
5.13 Emoji shortcode
当 render_emoji = false 时,可用 shortcode 插入:
{%% emoji(name="🦀") %%}5.14 本站自定义 shortcode
templates/shortcodes/ 下还有:
| Shortcode | 用途 |
|---|---|
badges | 徽章展示 |
polaroid | 宝丽来相框图片 |
window | 窗口 UI 框 |
masonry | 瀑布流图片墙 |
todo | TODO 列表 |
now_playing | 正在播放 |
online | 在线状态 |
用法均为 {%% name(参数) %%}...{%% end %%},具体参数见对应 html 文件。
六、模板开发注意点清单
- 不要改 theme:在
templates/覆盖或 extends。 safe过滤器:page.content、| markdown | safe输出已解析 HTML;纯文本勿加 safe。- Section 路径:
get_section(path="03Share_blog/_index.md")路径相对content/。 - 全局变量:
{%% set_global x = ... %%}在 loop 内累加时使用。 - CSP:嵌入 iframe / 外部脚本需在
zola.toml的[extra.csp]声明域名。 - 静态资源:JS/CSS 放
static/,引用/js/xxx.js;Sass 放sass/由 Zola 编译。 - Co-located 资源:图片与
index.md同目录,构建后 permalink 同路径,便于搬运整文件夹。 - 分页:
paginate_by = 10+ 模板中使用section.pages与 paginator partial。 - 多语言:
content/下按语言分子目录,配合i18n/*.toml。 - 调试:
zola build --force强制重建;zola serve --open热重载预览。
七、本站实践对照
| 功能 | 实现位置 |
|---|---|
| 文章页扩展(热力图、滚动条、音乐) | templates/article.html extends + include partials |
| 归档页 + 年份热力图 | templates/archive.html + heatmap_component.html |
| 文章页音乐播放器 | partials/music_player.html + static/js/music-player.js |
| 自定义列表模板 | templates/article_list.html / nanolog_list.html |
| 全局配置 | zola.toml → config.extra.* |
| 主题变量(颜色) | ametrine --bg-muted-1、--accent-color 等 CSS 变量 |
八、构建流程
8.1 音乐播放器:如何在新博客中启用
全站开关(zola.toml,已配置可跳过)
[extra.music_player]
enabled = true
base_url = "/music" # 对应 static/music/ → public/music/单篇文章 front matter
[extra.music_player]
enabled = true
tracks = [
{ file = "歌手-歌名" },
{ file = "周杰伦-青花瓷" },
]资源文件命名(放在 static/music/)
| 文件 | 说明 |
|---|---|
歌手-歌名.mp3 或 .flac | 音频;优先使用 MP3(体积更小、seek 更稳) |
歌手-歌名.lrc | 歌词;UTF-8 或 GB18030 |
file 字段不带扩展名,播放器自动探测 .mp3 → .flac。
行为摘要
- 挂件在文章页右上角(热力图下方),默认只显示播放按钮,悬停展开控制条。
- 进度条:细轨道 + 圆点,点击/拖动跳转。
- 音量:点击喇叭循环 25% → 50% → 75% → 100% → 静音。
- Safari 不显示播放器(脚本内检测后移除组件)。
8.2 构建与预览命令对照
| 场景 | 命令 | 说明 | 进度条能否立刻拖 |
|---|---|---|---|
| 日常预览 | zola build → zola serve | 改样式、普通文章足够 | 首次拖可能需等整首下载(Blob 兜底);之后正常 |
| 加密文章开发 | ./dev.sh | 先 encrypt-content.mjs,再 zola serve | 同上 |
| 正式部署 / CI | ./build-site.sh | 加密 → build → post-build → kanban 校验 | 线上 GitHub Pages 支持 Range,可直接拖(需 static/music/ 已部署) |
| 本地想立刻拖 | 见下方两行 | 可选;不改日常习惯 | 立刻可拖,与线上一致 |
日常预览与加密开发(标准流程,未改):
# 普通文章
zola build
zola serve
# 新增/修改加密文章
./dev.sh正式部署:
./build-site.sh
# CI 同:.github/workflows/deploy_pages.yml → ./build-site.sh --output-dir ../public_html本地立刻验证进度条 seek(可选):
zola build --base-url http://127.0.0.1:1111/
node scripts/serve-with-ranges.mjs --no-watch -p 1111然后访问 http://127.0.0.1:1111/。说明:
--base-url让构建出的 CSS/JS 链接指向本地,避免指向suchaharcan.github.io。- seek 能力来自
serve-with-ranges.mjs(发送Accept-Ranges: bytes),不是zola serve。 zola serve不支持 Range,故默认本地首次拖动会触发播放器 Blob 兜底(下载整首后再跳),不需要从头播到尾。
其他常用命令:
zola build --force # 清空 output 后重建
zola check # 检查链接,不输出站点设计细节与根因分析见 Nanolog · 热力图与音乐播放器。
8.3 原构建命令速查
./build-site.sh # 可选;若存在新增加密博客则必选
zola build --force
zola serve
zola check九、部署与发布
部署源码 参考
.github/workflows/deploy.yml
十、Zola.toml 配置 节点作用解读
全局(zola.toml)
title = "Rocky‘s Blog"
base_url = "https://suchaharcan.github.io/"
description = "月更 技术博客 CXX优先"
theme = "ametrine"
compile_sass = true
minify_html = true
feed_filenames = ["atom.xml", "rss.xml"] # 生成的 RSS/Atom 订阅文件
build_search_index = true # 生成搜索索引
author = "Suchaharcan"
taxonomies = [
{ name = "tags", feed = true, paginate_by = 10 },
{ name = "categories", feed = true },
] # 分类和标签的配置
[markdown]
render_emoji = false
smart_punctuation = true
lazy_async_image = false
bottom_footnotes = true # 脚注显示在底部
external_links_class = "external"
github_alerts = true # 显示 GitHub 警告
[markdown.highlighting]
style = "class"
light_theme = "monokai-pro-light"
dark_theme = "monokai-pro"
extra_themes = [
"themes/ametrine/giallo/themes/monokai-pro-light.json",
"themes/ametrine/giallo/themes/monokai-pro.json",
]
[extra]
# Put all your custom variables here
# 全站 Umami:static/analytic/umami.js(覆盖首页 / 文章 / 标签 / 404 等所有页面)
scripts = ["analytic/umami.js"]
feed_sections = [
{ name = "Nanolog", path = "@/nanolog/_index.md" },
{ name = "Blog", path = "@/01Write_blog/_index.md" },
] # 手动指定 哪些导航栏中的 RSS 可订阅项 sections
accent_color = ["hsl(270 13% 48%)", "hsl(290 20% 71%)"]
# home_url = "@/home/index.md"
issues_url = "https://github.com/SuchaharCan/SuchaharCan.github.io/issues/new" # 弃用
source_url = "https://codeberg.org/SuzhaharCan/SuzhaharCan.codeberg.page" # 网站源码在Codeberg ,可跳转直接在线修改博客, 在 kanban/ nanolog/ 中使用
replog_url = "https://github.com/SuchaharCan/SuchaharCan.github.io/actions/workflows/deploy_pages.yml" # 网站部署在 github.io, 可跳转点击 触发重新部署 。
copy_button = true
show_reading_time = true
show_backlinks = true
date_format = "%d %B %Y"
date_format_long = "%d %B %Y, %R (%Z)"
date_locale = "en_IE" # zola 暂不支持中文, 默认 英文
timezone = "Asia/Shanghai" # 时区, HTML/JS 业务逻辑判断 使用
show_comments_qr = false #评论二维码, 暂时禁用, 我有 社交账号,但我暂无 海外运营想法 禁用,若文章有价值, 我会直接 分享到HackerNews 上
csp = [
{ directive = "font-src", domains = [
"'self'",
] },
] # 内容安全策略,启用,限制外部脚本注入,提高网站 安全性, 若 后续功能开发的模块需要 JS脚本,此处需要 同步更新
[extra.music_player]
enabled = true
base_url = "/music" # 音乐资源:static/music/ → /music/单篇文章启用播放器:在文章 front matter 增加
[extra.music_player],见 §8.1。
手动指定 文章分类, 用于 文章列表页面 的 分类显示 大类划分 : 归档, 有价值, 热门
[[extra.categories]]
name = "Tracking"
description = "Posts that need to be continuously updated."
color = "green"
icon = "fire"构建脚本说明:dev.sh 与 build-site.sh
本站有两条常用入口脚本,分别对应本地开发预览与正式构建。二者都会在 Zola 构建前同步加密文章密文,但后续步骤不同。
一览
| 脚本 | 用途 | 输出 | 典型场景 |
|---|---|---|---|
./dev.sh | 本地开发 + 热重载预览 | 不强调完整 public/ 产物 | 改文章、改样式、调试加密页 |
./build-site.sh | 正式静态站点构建 | public/(或 --output-dir 指定目录) | 部署前、CI、需要完整校验 |
dev.sh — 本地开发
作用
在本地启动 Zola 开发服务器(zola serve),保存文件后自动重建并刷新预览。
执行步骤
① node scripts/encrypt-content.mjs # 同步加密文章密文
② zola serve [你传入的参数] # 本地预览(默认 http://127.0.0.1:1111)源码
node scripts/encrypt-content.mjs
exec zola serve "$@"何时使用
- 新增或修改了加密文章(
[extra.encryption] encrypt = true)时,需先跑密文同步再预览。 - 改普通文章、模板、样式、JS/CSS 时,也可用本脚本(密文同步幂等,多跑无害)。
不会做的事
- 不执行
post-build.mjs(RSS/Atom、搜索索引不会剔除加密文章条目)。 - 不执行
verify-kanban-build.mjs(看板产物完整性校验)。 - 不负责生成可部署的完整发布包;部署请用
build-site.sh。
常用示例
./dev.sh # 默认端口 1111
./dev.sh --open # 构建后自动打开浏览器
./dev.sh -p 3000 # 指定端口说明
zola serve不支持 HTTPAccept-Ranges,本地音乐播放器进度条首次拖动可能需 Blob 兜底(见 Nanolog2026-07-12)。- 若仅改非加密内容、密文已存在,也可手动:
zola build && zola serve(跳过加密同步)。
build-site.sh — 正式构建
作用
生成可部署的静态站点目录,并完成加密相关的构建后处理与看板校验。CI(.github/workflows/deploy_pages.yml)调用的是本脚本。
执行步骤
① node scripts/encrypt-content.mjs # 全量同步加密密文
② zola build [可选参数] # 输出静态 HTML 到 public/
③ node scripts/post-build.mjs # 从 RSS/Atom、搜索索引移除加密文章
④ node scripts/verify-kanban-build.mjs # 校验 kanban 周页是否均已生成各子步骤职责
| 步骤 | 脚本 | 说明 |
|---|---|---|
| 构建前 | encrypt-content.mjs | 扫描 content/,对 encrypt = true 的文章重加密;删除已取消加密的多余 JSON |
| 构建 | zola build | Zola 原生编译:Markdown → HTML,拷贝 static/ → public/ |
| 构建后 | post-build.mjs | 加密页不出现在订阅源与站内搜索索引中 |
| 构建后 | verify-kanban-build.mjs | 确保 content/kanban/YYYY-MM-DD.md 在输出目录均有对应页面 |
何时使用
- 推送 / 部署到 GitHub Pages 之前。
- 需要验证看板、加密、订阅源行为是否正确时。
- 本地想确认与线上一致的完整产物时。
常用示例
./build-site.sh
./build-site.sh --output-dir ../public_html # CI 用法;并 export ZOLA_OUTPUT_DIR 供后置脚本参数
- 支持将额外参数原样传给
zola build(如--output-dir)。 --output-dir会设置环境变量ZOLA_OUTPUT_DIR,供post-build.mjs与verify-kanban-build.mjs读取正确输出目录。
对比:何时用哪个
| 需求 | 推荐命令 |
|---|---|
| 本地边改边看 | ./dev.sh 或 zola serve |
| 改了加密文章并要本地解密预览 | ./dev.sh |
| 部署前完整构建 | ./build-site.sh |
| 只改样式、不涉及加密 | zola build && zola serve 即可 |
| 本地立刻验证音乐进度条 seek | zola build --base-url http://127.0.0.1:1111/ 后 node scripts/serve-with-ranges.mjs --no-watch -p 1111(可选,见模板指南 §8.2) |
与 CI 的关系
GitHub Actions 工作流 不调用 dev.sh,部署步骤为:
./build-site.sh --output-dir ../public_html与本地正式构建一致,无需单独改 workflow。
相关文件
| 路径 | 说明 |
|---|---|
scripts/encrypt-content.mjs | 构建前加密同步 |
scripts/post-build.mjs | 构建后 feed / 搜索过滤 |
scripts/verify-kanban-build.mjs | 看板产物校验 |
scripts/encryption-lib.mjs | 加密与 feed 处理共享库 |
scripts/serve-with-ranges.mjs | 可选:带 byte-range 的本地静态服务(非 dev.sh 默认流程) |
更细的加密架构与命令对照见:
参考
- Zola Documentation
- Tera Template Engine
- daudix.one content — 本文 Markdown 示例主要来源
- daudix: Zola vs Jekyll — 目录结构与模板覆盖的详细说明
- daudix: My Blog Workflow — front matter 模板与图片工作流
本文即按上述规范编写:toc = true 启用目录,accent_color 设置页面强调色,内部链接使用 @/ 语法。