kramdown 脚注语法

kramdown 脚注语法

根据 kramdown 官方语法文档中的 Footnotes 部分整理。
原文:https://kramdown.gettalong.org/syntax.html#footnotes

kramdown 的脚注写法和“引用式链接”很相似:

  1. 在正文中放置脚注标记;
  2. 在文档任意位置定义脚注内容;
  3. 转换为 HTML 时,正文中的脚注标记会变成可点击编号;
  4. 实际脚注内容通常统一输出在文档末尾。

脚注不是原始 Markdown 的标准语法,它来自 PHP Markdown Extra 一类的扩展语法。


1. 最基本的脚注

正文中这样引用脚注:

kramdown 是一个 Ruby 编写的 Markdown 解析器[^1]。

然后在文档其他位置定义脚注:

[^1]: kramdown 可以把 Markdown 转换为 HTML 等格式。

完整示例:

kramdown 是一个 Ruby 编写的 Markdown 解析器[^1]。

[^1]: kramdown 可以把 Markdown 转换为 HTML 等格式。

大致显示为:

kramdown 是一个 Ruby 编写的 Markdown 解析器¹。

1. kramdown 可以把 Markdown 转换为 HTML 等格式。

2. 脚注标记的格式

脚注标记使用方括号,内部以 ^ 开头:

[^1]

也可以使用有意义的名称:

[^source]
[^note]
[^ruby-version]

脚注名称应满足以下规则:

  • 必须以 ^ 开头;
  • ^ 后第一个字符必须是字母、数字或下划线一类的单词字符;
  • 后续可以继续使用字母、数字、下划线或连字符;
  • 名称只负责关联正文标记和脚注定义;
  • 页面上最终显示的脚注编号,不一定等于名称中的数字。

正确示例:

[^1]
[^note]
[^source-1]
[^ruby_guide]

不建议或可能无效的写法:

[^]
[^-note]
[^脚 注]

为了兼容性和可维护性,建议使用英文小写字母、数字和连字符:

[^install-note]

3. 脚注编号由出现顺序决定

脚注最终显示为第几个,不是由脚注名称决定,而是由脚注标记首次出现在正文中的顺序决定。

例如:

第一个出现的脚注[^99]。

第二个出现的脚注[^1]。

[^1]: 虽然名称是 1,但它第二个出现。
[^99]: 虽然名称是 99,但它第一个出现。

最终通常会显示为:

第一个出现的脚注¹。

第二个出现的脚注²。

因此,脚注名称最好用于表达含义,而不是依赖它控制编号:

正文内容[^source]。

补充说明[^compatibility]。

4. 脚注定义可以放在文档任意位置

脚注定义不需要紧跟在脚注标记后面。

下面三种位置通常都可以。

放在段落后面

正文内容[^note]。

[^note]: 这是脚注。

放在章节结尾

正文内容[^note]。

## 下一节

其他内容。

[^note]: 这是前面正文引用的脚注。

统一放在文档末尾

第一处说明[^first]。

第二处说明[^second]。

---

[^first]: 第一个脚注。
[^second]: 第二个脚注。

为了方便维护,推荐将脚注统一放在所属章节末尾,或者整篇文档末尾。


5. 脚注定义的基本结构

脚注定义由以下几部分组成:

脚注名称 + 冒号 + 脚注内容

基本格式:

[^name]: 脚注内容

冒号后可以有一个或多个空格:

[^name]:脚注内容
[^name]: 脚注内容
[^name]:     脚注内容

不过为了可读性,建议统一保留一个空格:

[^name]: 脚注内容

脚注定义前最多可以缩进三个空格:

   [^note]: 这仍然是脚注定义。

不建议主动缩进,最好顶格写:

[^note]: 推荐写法。

6. 脚注内容支持 Markdown

脚注内容会按块级 Markdown 处理,所以其中可以使用:

  • 强调;
  • 链接;
  • 行内代码;
  • 多个段落;
  • 引用;
  • 列表;
  • 代码块;
  • 其他块级元素。

强调和行内代码

正文[^format]。

[^format]: 这里可以使用 **粗体**、*斜体* 和 `行内代码`。

链接

正文[^website]。

[^website]: 参见 [kramdown 官网](https://kramdown.gettalong.org/)。

多个行内元素

正文[^detail]。

[^detail]: `auto_ids` 选项用于控制标题 ID,默认值通常是 `true`。

7. 多行脚注

脚注内容较长时,可以继续写到下一行。

后续行通常需要缩进四个空格或一个 Tab:

正文中引用一个较长的脚注[^long]。

[^long]: 这是脚注第一行。
    这是脚注第二行。
    这是脚注第三行。

为了避免不同解析器对连续文本的处理差异,推荐把长文本整理得更明确:

正文中引用一个较长的脚注[^long]。

[^long]: 这是脚注第一行,
    这是脚注第二行,
    这是脚注第三行。

如果只是普通段落,不必为了换行效果强行拆行。也可以写成一行:

[^long]: 这是一个内容比较长、但仍然作为单个段落处理的脚注。

8. 脚注中包含多个段落

第二个段落及后续内容应整体缩进四个空格:

正文[^multi]。

[^multi]: 这是脚注的第一段。

    这是脚注的第二段。

    这是脚注的第三段。

完整示例:

kramdown 的脚注可以包含多个段落[^explain]。

[^explain]: 第一段用于给出简要说明。

    第二段可以继续补充技术细节。

    第三段还可以给出注意事项。

空行本身也应位于脚注定义结构中。最稳妥的方式是:第二段开始后,所有内容都缩进四个空格。


9. 脚注中包含引用

脚注内容可以以引用开头:

正文[^quote]。

[^quote]:
    > 这是脚注中的引用。

也可以先写普通段落,再放引用:

正文[^quote]。

[^quote]: 这是脚注的说明。

    > 这是脚注中的引用内容。

注意:当脚注定义的第一行冒号后没有正文时,后续块级内容需要正确缩进。


10. 脚注中包含列表

正文[^list]。

[^list]: 注意以下几点:

    - 第一项;
    - 第二项;
    - 第三项。

有序列表:

正文[^steps]。

[^steps]: 操作步骤:

    1. 安装 kramdown;
    2. 创建 Markdown 文件;
    3. 转换为 HTML。

11. 脚注中包含代码块

代码块本身需要四个空格缩进,而脚注内容已经需要四个空格,因此代码块通常总共需要八个空格。

正文[^code]。

[^code]:
        puts "这是脚注中的代码块"

更完整的示例:

Ruby 中可以这样调用 kramdown[^ruby-code]。

[^ruby-code]:
        require "kramdown"

        source = "# Hello"
        puts Kramdown::Document.new(source).to_html

这里代码行前相当于有八个空格:

脚注内容缩进 4 个空格
+
代码块额外缩进 4 个空格
=
总共 8 个空格

为什么下面不是代码块

[^note]:       这通常仍然只是普通文字

冒号后第一行开头的额外空格会被剥离,所以不能单靠冒号后增加很多空格,把第一行变成代码块。

需要让代码块成为脚注的第一个元素时,推荐写成:

[^note]:
        puts "真正的代码块"

也就是:

  • 脚注定义行在冒号后结束;
  • 下一行缩进八个空格;
  • 代码块从下一行开始。

12. 同一个脚注可以引用多次

相同名称的脚注标记都会指向同一个脚注定义:

第一次引用[^same]。

中间还有其他内容。

第二次引用同一个脚注[^same]。

[^same]: 两个标记都指向这个脚注。

它们不会生成两个不同的脚注内容。

实际 HTML 中是否为每个引用生成独立返回链接,取决于转换器的实现。


13. 没有定义的脚注不会正常生成

如果正文中出现脚注标记,但文档中没有对应定义:

这里有一个没有定义的脚注[^missing]。

kramdown 不会把它正常转换为脚注链接。

因此发布前应检查:

  • 正文中的每个脚注标记都有定义;
  • 脚注名称完全一致;
  • 没有拼写错误;
  • 大小写是否保持一致。

错误示例:

正文[^Source]。

[^source]: 名称大小写不一致。

推荐:

正文[^source]。

[^source]: 名称完全一致。

14. 未被引用的脚注定义会被忽略

如果只定义脚注,却没有在正文中引用:

正文没有引用任何脚注。

[^unused]: 这个脚注没有被引用。

这个脚注定义通常不会出现在最终脚注区域中。

这有利于避免输出无用脚注,但也可能隐藏维护错误。删除正文内容后,应检查是否留下未使用的脚注定义。


15. 同名定义只保留最后一个

如果同一个脚注名称被定义多次,通常只有最后一个定义生效:

正文[^note]。

[^note]: 第一个定义。

[^note]: 第二个定义。

最终使用:

第二个定义。

不要故意依赖覆盖行为。推荐确保每个脚注名称只定义一次。


16. 脚注不能放在链接文字中

下面这种写法不允许:

[链接文字中包含脚注[^note]](https://example.com)

原因是脚注标记在 HTML 中会被转换为链接,而普通 Markdown 链接本身也是链接,最终会形成“链接嵌套链接”。

HTML 不允许这种结构:

<a href="https://example.com">
  链接文字
  <a href="#fn-note">1</a>
</a>

正确做法是把脚注放到链接后面:

[示例网站](https://example.com)[^note]

[^note]: 这是对这个链接的补充说明。

或者放在完整句子末尾:

可以访问 [示例网站](https://example.com) 查看详情[^note]。

17. 脚注标记上的属性会被忽略

一般行内元素可以通过 IAL 添加属性:

*文字*{: .important}

但脚注标记后附加的行内属性通常不会生效:

正文[^note]{: .important}。

[^note]: 脚注内容。

不要依赖这种方式给脚注编号添加类或其他属性。

需要自定义脚注样式时,应通过:

  • HTML 转换器输出结构;
  • 主题 CSS;
  • kramdown 相关配置;
  • 自定义转换器。

18. 可以给脚注定义附加块级属性

虽然脚注定义本身属于“非内容块级元素”,但可以对定义附加块级属性列表。

正文[^note]。

[^note]: 脚注内容。
{: .legal-note}

属性最终如何使用,取决于具体转换器。

有些转换器可能把属性用于生成的脚注元素,有些转换器可能忽略部分属性。因此不能假定所有输出格式表现一致。


19. 脚注内容最终通常位于文档末尾

无论脚注定义写在文档哪里,引用到的脚注内容通常都会统一输出在最终文档的脚注区域。

源文件:

第一段正文[^first]。

[^first]: 第一个脚注定义。

第二段正文[^second]。

[^second]: 第二个脚注定义。

最终页面结构通常类似:

<p>第一段正文<sup>...</sup>。</p>

<p>第二段正文<sup>...</sup>。</p>

<div class="footnotes">
  <ol>
    <li>第一个脚注定义。</li>
    <li>第二个脚注定义。</li>
  </ol>
</div>

具体标签、类名、ID 和返回链接由 HTML 转换器决定。


20. 推荐命名方式

不推荐只使用连续数字:

[^1]
[^2]
[^3]

数字较少时可以使用,但文档变长或调整顺序后不容易维护。

推荐使用有意义的名称:

[^source]
[^version]
[^compatibility]
[^security-note]

示例:

kramdown 的语法与原始 Markdown 并不完全一致[^compatibility]。

[^compatibility]: kramdown 为了让解析规则更明确,对部分边界行为作了调整。

名称不会决定显示编号,因此可以放心使用描述性标识。


21. 中文标点放在哪里

脚注标记和句末标点的位置会影响阅读效果。

说明整句话

推荐把脚注放在句号前:

kramdown 使用 Ruby 编写[^source]。

显示时类似:

kramdown 使用 Ruby 编写¹。

只说明某个词

脚注紧跟在该词后:

kramdown[^name] 是一个 Markdown 解析器。

不建议把脚注和说明对象隔得太远

不推荐:

kramdown 是一个 Markdown 解析器。[^source]

这种写法不是不能解析,但在中文排版中,脚注通常紧跟被说明的文字或句子,并放在句末标点之前。


22. 一个脚注包含完整说明

kramdown 的默认输入语法并不等同于 GitHub Flavored Markdown[^gfm]。

[^gfm]: 如果需要更接近 GitHub 的解析行为,可以安装
    `kramdown-parser-gfm`,并将输入解析器设置为 `GFM`:

        gem install kramdown-parser-gfm

    Jekyll 配置示例:

        kramdown:
          input: GFM

这个示例同时包含:

  • 普通段落;
  • 行内代码;
  • 代码块;
  • YAML 配置。

23. 法律文档脚注示例

本法自2026年1月1日起施行[^effective-date]。

[^effective-date]: “施行日期”表示法律规范开始发生效力的日期。

带来源链接:

该条文后来经过修订[^amendment]。

[^amendment]: 修订信息参见
    [全国人民代表大会官方网站](https://www.npc.gov.cn/)。

带多段解释:

本条所称“主管部门”应结合上下文确定[^authority]。

[^authority]: 第一,应检查本法总则或者附则中是否存在专门定义。

    第二,如果本法没有定义,应结合相关行政法规和部门职责规定判断。

    第三,不宜仅根据部门名称作字面推断。

带代码化来源信息:

该版本来源于正式发布文本[^metadata]。

[^metadata]: 文档元数据:

        source_type: official
        publication_date: 2026-01-01
        status: effective

24. 常见错误

错误一:忘记写 ^

错误:

正文[note]。

[note]: 脚注内容。

这是引用式链接语法,不是脚注。

正确:

正文[^note]。

[^note]: 脚注内容。

错误二:定义名称不一致

错误:

正文[^note-one]。

[^note-1]: 脚注内容。

正确:

正文[^note-one]。

[^note-one]: 脚注内容。

错误三:多段脚注没有缩进

错误:

[^note]: 第一段。

第二段。

这里“第二段”会成为普通正文,不属于脚注。

正确:

[^note]: 第一段。

    第二段。

错误四:代码块缩进不足

错误:

[^code]:
    puts "Hello"

这通常只是脚注中的普通文本,因为四个空格主要用于进入脚注内容。

正确:

[^code]:
        puts "Hello"

错误五:把脚注放在链接文字内部

错误:

[网站[^note]](https://example.com)

正确:

[网站](https://example.com)[^note]

错误六:重复定义

不推荐:

[^note]: 旧内容。
[^note]: 新内容。

推荐只保留一个定义:

[^note]: 新内容。

25. 最小可复制模板

正文中需要补充说明的内容[^note]。

[^note]: 这里写脚注内容。

多段脚注模板:

正文中需要详细说明的内容[^detail]。

[^detail]: 这是脚注第一段。

    这是脚注第二段。

    - 可以包含列表;
    - 也可以包含其他块级内容。

含代码块的模板:

正文中引用代码示例[^code]。

[^code]:
        puts "Hello"

26. 完整演示

---
layout: default
title: kramdown 脚注示例
---

# kramdown 脚注示例

kramdown 是一个 Ruby 编写的 Markdown 超集解析器[^intro]。

它的脚注名称不决定最终编号[^numbering],同一个脚注也可以引用多次[^repeat]。

这里再次引用同一个脚注[^repeat]。

## 示例代码

Ruby 中可以这样转换 Markdown[^code-example]。

[^intro]: kramdown 可以把 Markdown 转换为 HTML、LaTeX 等格式。

[^numbering]: 脚注编号按照脚注标记首次出现在正文中的顺序生成。

[^repeat]: 名称相同的脚注标记指向同一个脚注定义。

[^code-example]:
        require "kramdown"

        source = "# Hello"
        html = Kramdown::Document.new(source).to_html

        puts html

27. 使用建议

  1. 使用有意义的脚注名称,例如 [^source],不要完全依赖数字。
  2. 将脚注定义统一放在章节末尾或文档末尾。
  3. 脚注标记紧跟需要说明的文字。
  4. 中文句子中通常将脚注标记放在句末标点前。
  5. 多段脚注的后续段落统一缩进四个空格。
  6. 脚注中的缩进代码块通常需要八个空格。
  7. 不要在普通链接的链接文字中嵌套脚注。
  8. 发布前检查未定义脚注、未引用脚注和重复定义。
  9. 不要依赖脚注标记后的行内属性列表。
  10. 不同转换器可能生成不同 HTML 结构,应结合最终输出测试样式。

28. 官方规则摘要

kramdown 脚注的核心规则可以概括为:

正文标记:
[^name]

脚注定义:
[^name]: 内容

并且:

  • 脚注定义可以放在文档任意位置;
  • 显示编号由正文中首次出现的顺序决定;
  • 同名标记引用同一个脚注;
  • 未定义的标记不会生成有效脚注;
  • 未被引用的定义会被忽略;
  • 重复定义时最后一个生效;
  • 脚注内容可以包含块级 Markdown;
  • 脚注不能嵌套在链接文字中;
  • 脚注标记上的行内属性会被忽略;
  • 引用到的脚注通常统一输出到文档末尾。
下一篇 kramdown 完整语法中文指南