前置知识: Markdown

脚注

9 min中级

Markdown 脚注语法:标记与定义的配对模型、为什么需要脚注、定义位置无关渲染顺序、多平台兼容性与遮代码自检实践。

1. 脚注概述

1.1 什么是脚注

脚注(Footnote)允许在文档中添加补充说明,读者可以点击上标标记跳转到文末的详细注释。脚注常用于:

  • 学术论文中的引用来源
  • 技术文档中的补充说明
  • 长文中的额外细节,避免打断正文阅读流

为什么需要它:写作时经常要在”正文流畅”与”信息严谨”之间做交换——来源、勘误、边角细节都值得写,但直接插进正文会压断主线。脚注把这笔交易做成了机制:正文只留一个上标,重量全部移到页面底部,愿意深究的读者点一下,赶时间的读者一行都不用看。它是”先给主线、按需展开”的信息分层设计。

1.2 脚注与尾注

类型位置适用场景
脚注页面底部学术论文、技术文档
尾注文档末尾书籍、长篇报告
行内注释紧跟正文简短补充

Markdown 中的脚注实际上是尾注——所有脚注内容统一显示在文档末尾。

1.3 心智模型:标记与定义是靠标签配对的两个独立元素

学脚注最容易卡住的地方是”定义到底写在哪”。正确的模型是把它想成变量与引用:

  • [^note] 是引用标记:写在正文里,决定”哪里出现上标”;
  • [^note]: 内容 是定义:写在文档任何位置,决定”点开上标看到什么”;
  • 两者只靠标签名(note)配对,物理位置完全分离。

由此直接推出三条规则(不用死记):

  1. 定义写在哪都不影响渲染——渲染器扫描全文收集定义,统一搬到末尾;
  2. 显示编号是渲染器按”引用出现顺序”自动编排的,与标签名无关:[^zuihou] 若是正文第一个被引用的脚注,就显示为 [1];
  3. 没有被任何标记引用的定义是”未使用的变量”——多数渲染器(含 GitHub)直接不渲染它,写了对不引用等于没写。

这套”正文干净、定义后置、按名配对”的结构,与参考式链接是同一个思想:长文档里把资源定义集中管理,正文只留短引用。

2. 脚注语法

2.1 基本语法

markdown
这是一段正文[^1],其中包含脚注引用。

也可以使用描述性标签[^note]。

[^1]: 这是第一个脚注的内容。

[^note]: 这是描述性标签的脚注内容。

渲染效果:

  • 正文中的 [^1] 显示为上标数字 [^1]
  • 点击上标可跳转到文末脚注
  • 文末脚注带有返回链接

2.2 脚注定义规则

markdown
<!-- 规则一:脚注定义可放在文档任意位置 -->

正文内容[^1]。

<!-- 脚注定义可以放在文档末尾 -->

[^1]: 脚注内容。

<!-- 规则二:脚注定义需要空行分隔 -->

[^1]: 第一个脚注。

[^2]: 第二个脚注。

<!-- 规则三:多行脚注使用缩进 -->

[^long]:
    这是第一行。
    这是第二行(缩进4个空格)。
    这是第三行。

规则一的深一层读法:正因为”定义位置无关渲染”,实践里才有一条团队约定——定义统一放文末。渲染结果相同,但定义散落正文会让后续维护者找不到”所有脚注”的全景,文末集中存放让脚注清单本身成为文档的参考文献区。

2.3 脚注标签类型

类型语法显示效果适用场景
数字标签[^1][1]顺序引用
描述标签[^source][source]语义化引用
混合使用[^1] [^note]各自显示灵活场景

实践建议:标签一律用语义化命名([^bench]、[^rfc9110]),数字标签只留给”注定一次性”的脚注。原因与变量命名相同:后来者在正文里看到 [^4] 无法知道它是什么,看到 [^perf-data] 可以;而且在中间插入一个新脚注时,语义化标签不需要把后续所有编号重排一遍(显示编号本来就是自动的)。

3. 多平台支持

3.1 支持情况

平台支持脚注语法说明
GitHub支持[^1]2021 年 9 月起全站支持
GitLab支持[^1]原生支持
Obsidian支持[^1]原生支持,支持行内脚注
Typora支持[^1]原生支持
Hugo支持[^1]Goldmark 默认启用
Jekyll视配置[^1]依赖所用 Markdown 处理器
CommonMark不支持—标准不支持
GFM 规范文档未收录—脚注是 cmark-gfm 扩展,未写入正式规范文档

这张表是”扩展语法的平台税”的典型样本:功能好用,但不在 CommonMark 核心里。跨平台发布的文档(同一份 md 既进 GitHub 又进静态站点又进 PDF 转换)要先用目标渲染器过一遍,脚注尤其如此——它一旦不被支持,[^1] 会原样出现在正文里,比”功能缺失”更难看。

3.2 GitHub 脚注

GitHub 于 2021 年 9 月正式支持脚注语法(cmark-gfm 的 footnotes 扩展):

markdown
GitHub 现在支持脚注了[^1]!

[^1]: 2021 年 9 月,GitHub 宣布在所有 Markdown 字段支持脚注语法。

GitHub 脚注特性:

  • 脚注内容显示在文档底部
  • 点击上标跳转到脚注
  • 脚注旁有返回箭头
  • 数字标签自动编号

3.3 Obsidian 脚注

Obsidian 支持标准脚注语法,还支持行内脚注:

markdown
<!-- 标准脚注 -->

正文内容[^1]。

[^1]: 脚注定义。

<!-- 行内脚注(Obsidian 特有) -->

正文内容^[这是行内脚注,无需单独定义。]

行内脚注把”标记与定义分离”的模型重新合体:内容就地写,渲染时仍搬到文末。它解决了”短注释不想跳到文末维护”的场景,但这是 Pandoc/Obsidian 私有语法——写进要发到 GitHub 的文档会原样暴露 ^[...]。跨平台文档用标准语法,个人笔记库才用行内脚注。

4. 脚注高级用法

4.1 多次引用同一脚注

markdown
TypeScript[^ts] 是 JavaScript 的超集。
TypeScript[^ts] 添加了静态类型检查。

[^ts]: TypeScript 由 Microsoft 开发,2012 年首次发布。

同一脚注可以多次引用,渲染时使用相同的上标标记。典型场景:多个论断共享同一个来源——来源只列一次,引用处处可点。

4.2 脚注中的 Markdown

脚注内容支持行内 Markdown 语法:

markdown
正文引用[^api]。

[^api]: 参见 [API 文档](https://example.com/api) 中关于 `fetch()` 方法的说明。

边界提示:脚注内容里不能再嵌套脚注(标记会被当字面文本),也不支持块级元素;多行内容用 2.2 的缩进续行写法。

4.3 学术引用格式

markdown
根据 Smith 等人的研究[^smith2023],深度学习在自然语言处理领域取得了显著进展。

[^smith2023]: Smith, J., et al. "Deep Learning for NLP: A Survey." _Journal of AI Research_, vol. 45, 2023, pp. 123-156.

5. 常见坑

坑一:定义了但没引用,脚注消失。 [^x]: 内容 写了,正文却没有 [^x] 标记——渲染器不输出它(见 1.3 的”未使用变量”类比)。排查顺序固定:先全文搜标记,再搜定义,两端都要在。

坑二:标签重复定义。 两处写了 [^1]: ...,不同渲染器行为不一(取第一个或取最后一个),结果不可预测。语义化命名(坑外的建议同 2.3)能大幅降低撞名概率。

坑三:多行内容没缩进。 续行顶格写会被当成新段落,脱离脚注;续行必须缩进(4 空格或与首行内容对齐)。

坑四:在脚注里再放脚注或代码块。 标记原样显示、代码块被切断。脚注里只有行内语法可用。

坑五:把脚注当评论系统用。 大段设计讨论、给协作者的留言塞进脚注,文档会越来越难读。脚注是”补充证据与出处”,不是评论区——那种内容该去 issue 或 PR 讨论。

6. 替代方案

6.1 不支持脚注时的替代

当目标平台不支持脚注时,可以使用以下替代方案:

方案一:行内链接

markdown
根据研究[1],结论如下。

[1] Smith, J. "Deep Learning Survey." 2023.

方案二:HTML 锚点

markdown
根据研究<a href="#ref1">[1]</a>。

<a name="ref1"></a>

1. Smith, J. "Deep Learning Survey." 2023.

方案三:引用块

markdown
根据研究[1],结论如下。

> **[1]** Smith, J. "Deep Learning Survey." 2023.

三种替代的共同思路是手工模拟”标记 + 文末定义”:方案一连跳转都没有,方案二用 HTML 恢复跳转,方案三至少让来源在视觉上成组。它们都失去了自动编号——这正是标准脚注不可替代的部分。

6.2 Pandoc 脚注

Pandoc 支持更丰富的脚注语法:

markdown
<!-- 行内脚注 -->

正文^[这是行内脚注。]

<!-- 引用式脚注 -->

正文[^cite]

[^cite]: Smith, J. "Paper Title." 2023.

7. 动手实践:遮代码自检

先只读任务与提示,自己写完再对照参考实现。

任务:把下面这段”行内括号注释”风格的文字改写成标准脚注版,要求——三个补充说明全部变成脚注;其中”发布年份”这个来源被正文两处引用(只定义一次);脚注标签全部语义化;脚注内容里带一个链接。

Rust(发布于 2015 年,1.0 版,Mozilla 主导)是一门系统级语言。它的所有权模型(详见官方 Book,链接 https://doc.rust-lang.org/book/)让内存安全无需垃圾回收。2024 年 Rust 已进入 Linux 内核(6.1 起合入初步支持)。

提示:先找出三个”括号里”的信息块(发布信息 /所有权 Book / 内核支持),分别给语义化标签;注意”发布于 2015 年”与”Mozilla 主导”要共用同一个来源标记(回看 4.1)。

参考实现(先自己写完再看):

markdown
Rust[^rust-release] 是一门系统级语言。它的所有权模型[^rust-book]让内存安全
无需垃圾回收。2024 年 Rust 已进入 Linux 内核[^rust-kernel]。

[^rust-release]: 1.0 版发布于 2015 年,由 Mozilla 主导,另见
    [Rust Blog](https://blog.rust-lang.org)。
[^rust-book]: 官方教程见 [The Rust Programming Language](https://doc.rust-lang.org/book/)。
[^rust-kernel]: Linux 6.1 起合入 Rust 初步支持,状态见内核邮件列表存档。

要点自查:三个标签都是语义化的;[^rust-release] 在正文只出现一次但承担了两个括号的信息——若原文明里两处提到”2015”,就该引用两次;链接写在脚注定义内(4.2);多行定义的续行有缩进(坑三)。

8. 与之前和之后的知识的关系

  • 往前:链接与图片 的参考式链接是脚注的结构前身——都是”正文短引用、定义集中管理”;自动链接 解释了脚注里裸 URL 与带文字链接的差异;
  • 横向:转义字符 中 [^ 不属于需转义字符,脚注标记不会被转义打碎;
  • 往后:规范文档写作 里,脚注承接”引用标准、给出处”的角色;写学术论文或 RFC 风格文档时,1.1 的信息分层思想会反复用到。

小结

  • 初学者要点:正文写 [^1] 标记、文末写 [^1]: 内容 定义;GitHub、GitLab、Obsidian、Typora 都支持;点击上标跳转、脚注旁可返回。
  • 进阶注意:脚注是扩展语法而非 CommonMark 核心,纯规范渲染器原样显示;心智模型是”标记与定义靠标签配对的两个独立元素”——定义位置无关渲染、显示编号按引用顺序自动编排、未被引用的定义不渲染;标签建议语义化命名;行内脚注 ^[...] 是 Pandoc/Obsidian 私有语法,GitHub 不支持;同一标签可多处引用;不支持脚注的平台用”手写编号 + 文末列表”兜底,但失去自动编号。