编写页面
本页覆盖一页文档的完整写法:文件位置、front matter、标题锚点、链接、图片、草稿与页尾。前提是站点已能本地构建,尚未搭起时先看十分钟上手。
新建一页
页面是 content/ 下的 Markdown 文件,URL 由它在 content/ 里的位置决定:content/docs/install.md 发布为 /docs/install/。中文译文是同目录下的 .zh.md 同名文件,与英文页共享同一条逻辑路径。
没有附带资源的页面写成单个文件。页面带图片、cast、示例配置这类资源时改成一个目录,页面本身命名为 index.md,资源与它同放,这是 Hugo 的页面包(page bundle):
content/ 里的两种页面形态
content/
docs/
- _index.md栏目首页,英文
- _index.zh.md栏目首页,中文
- install.md单文件页面 → /docs/install/
- install.zh.md它的中文译文
anatomy/页面包 → /docs/anatomy/
- index.md
- index.zh.md
- shell.webp页面资源,两种语言共用
hugo new content docs/install.md 用 archetype 生成一个带 front matter 的空文件,见 Hugo 文档;手写文件同样可行。
中文页没有英文对等页时,Hugo 不会把无语言后缀的资源分给它。这种情况下资源文件名要带 .zh.(shell.zh.webp),正文里仍然写 shell.webp。
必要的 front matter
文件开头两行 --- 之间是 YAML front matter。四个键每页都应写上:
description 用一句话说清这页让读者做成什么。它出现在栏目首页的卡片、搜索结果与社交卡片中。weight 决定侧栏顺序,weight 相同时才退回字母序。
其余的键可选:图标、草稿、搜索权重、评论开关、页面外壳等,全表见页面参数。
标题层级与稳定锚点
正文用 ## 开始分节,# 留给 title。主题已渲染页面大标题,正文里再写一个 # 会出现两个一级标题。右栏的页面目录从 ## 开始收,收到第几级由 Hugo 的 markup.tableOfContents 决定,本站是 ####。
每个 ## 与 ### 都要手写英文锚点 {#id}:
理由有两条:
- 中英对齐。Hugo 从标题文字生成 ID,中文标题生成中文 ID:
/docs/install/#prerequisites与/zh/docs/install/#前提条件指向同一个语义位置,却是两个锚点,翻译审计无法比对。译文标题写上英文页的 ID,两边即同一个片段。 - 链接稳定。标题文字会随措辞调整而改变,公开链接不应随之失效。显式 ID 一旦发布即视为公开路由;需要改名时保留旧 ID 的空锚点:
ID 用短横线小写英文,全页唯一。本站的翻译审计脚本会比对英文页与中文页渲染出的标题 ID,不一致就报错。
链接写法
三种写法,用途不同:
| 写法 | 例子 | 什么时候用 |
|---|---|---|
| 站内绝对路径 | [配置总览](/zh/docs/customize/config/) |
默认写法。指向已发布的路由,便于审计与全站替换,不受源码文件移动影响 |
| 相对路径 | [另一页](../organize/)、 |
同一页面包内的资源,或有意跟着源码目录走的相邻页面 |
ref / relref shortcode |
[配置总览]({{< ref "/docs/configure/overview" >}}) |
需要构建期校验目标存在时;目标缺失时构建失败,不会留下死链 |
三种写法都带尾部斜杠,指向目录形式的路由(/zh/docs/write/pages/),与 Hugo 的默认永久链接一致。
主题没有链接渲染钩子,链接原样交给 Goldmark:外链不会自动加 target="_blank",需要新标签页时写成 HTML,或在站点自己的 layouts/_markup/render-link.html 里处理。
普通 Markdown 链接不做存在性检查。因此:
- 站内链接优先写绝对路径,改结构后用
grep全站替换; - 移动页面时给旧路径加
aliases,同时把站内链接改到新路由,不要让 alias 长期承担导航; - 拿不准的目标用
ref,让构建替你检查。
双语页面链接到逻辑页面(/zh/docs/write/pages/),不要链接 .zh.md 文件名;片段 ID 保持语言中立。
图片位置
页面自己的截图放页面包,多页共用的图放 assets/images/,不需要处理的大文件放 static/。三处在源码里都写成 ,属性行控制图注、尺寸、缩放与编号,见图片。
草稿与发布
draft: true 的页面不会进入构建产物:
预览时用 hugo server -D 显示草稿(-D 即 --buildDrafts)。date 写在未来的页面同样被排除,用 -F 显示。生产构建不加这两个开关,hugo 默认只发布已定稿的内容。
OINK 的 Markdown 扩展一览
正文是标准 Markdown(Goldmark),加上下面这些原生形态。它们都是普通 Markdown 语法加一行属性,在 GitHub 上按源码阅读同样可读:
| 组件 | 最短语法 | 页面 |
|---|---|---|
| 提示块 | 块引用首行写 > [!NOTE] |
提示块 |
| 标签页 | 相邻的两个围栏各加 {tab="Homebrew"} |
标签页 |
| 步骤 | 有序列表后面跟一行 {.steps} |
步骤 |
| 卡片 | 链接列表后面跟一行 {.cards} |
卡片 |
| 参数表 | 表格后面跟一行 {.fields meta="type default"} |
参数表 |
| 表格增强 | 表格后面跟一行 {.matrix}、{caption="…"} |
表格 |
| 代码块 | 围栏信息行写 {title="hugo.yml" copy=false} |
代码块 |
| 图片 | 独立成段的图片后面跟一行 {caption="…" width="600"} |
图片 |
| 文件树 | filetree 围栏,每行一个 - 名字/ # 注释 |
文件树 |
| 公式 | math 围栏,或用 $$ 包住的块级公式 |
公式 |
| 图表 | mermaid 围栏(还有 plantuml、markmap、echarts) |
Mermaid |
剩下的少数组件(徽章、按键、引用文件、终端录像、Book 的图表式例)用 shortcode,语法与参数见组件总览。
组合例子:步骤里放代码围栏与提示块。
- 安装 Hugo Extended,最低 0.160.1:
- 克隆文档站并预览:
提示
加
-D连草稿一起预览。
页尾的自动内容
页面末尾的四块内容由主题按固定顺序生成,不必在正文里写:
| 位置 | 是什么 | 默认 | 怎么改 |
|---|---|---|---|
| 1 | 反馈:「这页有帮助吗」两个按钮 | 关 | 仓库与页面信息 |
| 2 | 最后修改:时间加最近一次提交的标题,链到 GitHub | 有 Git 信息时开 | 仓库与页面信息 |
| 3 | 翻页器:上一页 / 下一页,顺序与侧栏树一致 | docs / book / blog 开 | 导航与菜单 |
| 4 | 评论:giscus | 配置完整且开启时 | 启用评论 |
标题旁边的操作菜单(复制 Markdown、编辑本页、查看历史、提 issue、打印)也是自动的,同样在仓库与页面信息里配置。
单页关闭其中某一块用 front matter:feedback: false、annotation: false、pager: false、comments: false。键的含义见页面参数。
验证
写完一页,运行一次严格构建:
- 输出必须以
Total in …结束,没有 ERROR、没有 WARN。属性行写了不允许的键、组件参数非法、ref目标不存在,都在这一步失败并指出文件与行号;主题不做静默降级。 --printPathWarnings报出两个页面指向同一输出路径的情况,多语言站或改过permalinks时较常出现。
在浏览器里确认三项:
- 侧栏里出现了这一页,位置符合
weight; - 右栏目录列出了你写的
##,点击后 URL 里的锚点是英文; - 中英两个版本的同名标题锚点一致(本站有
node scripts/check-doc-translations.mjs --public public做这项审计)。
相关
- 组织内容 — 目录结构如何决定侧栏
- 页面参数 — front matter 全表
- 组件总览 — 每个组件的语法与参数
- 多语言 — 双语对等文件与缺译回退
- 本地预览 —
hugo server的常用开关