Markdown ID,为什么不能以数字开头?
副标题:深入探究 Markdown 解析器的自动生成与手动指定之谜
在使用 Markdown 编写文档时,我们常常会为标题(Header)手动指定 ID,以便创建能直接跳转到特定区域的链接。通常情况下,像下面这样操作是完全没问题的。
### 一个很棒的标题 {#my-awesome-title}
...
[跳转到上面的标题](#my-awesome-title)
但如果遇到这种情况呢?比如,我们想用 1-section
作为 ID 来表示“第 1 章”。
### 第1章. 前言 {#1-section}
您是否也曾经历过这种 ID 无法正常工作,导致链接失效的 frustrating 经历?请放心,这不是 Bug,而更像是 Markdown 解析器(parser)的一种有意为之的设计。
本文将为您清晰地解释为什么以数字开头的 Markdown ID 会引发问题,并告诉您解决这个问题的最佳方法。
一切问题的根源:与 CSS 的冲突
这个问题的根本原因不在于 Markdown 本身,而在于 Markdown 最终转换成的 HTML 与 CSS 之间的关系。
- HTML 标准:在旧的 HTML4 标准中,ID 是不允许以数字开头的。虽然在 HTML5 中这一规则有所放宽,从语法上讲
id="1-section"
是有效的。 - CSS 选择器的局限:真正的问题出在 CSS。CSS 使用
#
符号来选择 ID。例如,id="my-id"
在 CSS 中用#my-id
来选择。但如果 ID 是1-section
,CSS 解析器就无法正确识别#1-section
。它会把#
后面的1
当作一个数值来解析,从而导致选择器(Selector)失效。
为了避免这种潜在问题,大多数 Markdown 解析器会有意阻止或不允许用户手动指定以数字开头的 ID。这可以说是一种“安全机制”。
“那为什么 ### 1. 标题
会自动创建 ID 呢?”
这一点让很多人感到困惑。很明显,当您像下面这样写时:
### 1. 前言
解析器会自动生成类似 <h3 id="1-前言">
这样以数字开头的 ID。为什么会存在这种差异呢?
核心在于,解析器对**“自动生成”和“手动指定”**的处理方式是不同的。
区别 | 自动生成的 ID (### 1. 前言 ) |
手动指定的 ID ({#1-section} ) |
---|---|---|
控制方 | 由 Markdown 解析器根据内部规则生成 | 由用户强制指定特定 ID |
适用规则 | 解析器可自行控制,规则相对灵活 | 作为外部输入,适用更严格的验证规则 |
目的 | 自动化创建一致的文档结构 | 为实现特定目的而强制指定 ID |
结果 | 可创建 id="1-前言" 可行 ✅ |
创建 id="1-section" 被阻止 ❌ |
也就是说,解析器确信自己创建的 ID 在其生态系统内可以被正确处理,但它无法保证用户输入的 ID 不会在外部(如 CSS、JavaScript)引发问题,因此强制执行最安全的规则(以字母开头)。
解决方案:应该怎么做?
既然了解了原因,我们就可以找到解决方案了。
方法一:以字母开头 (最推荐的方法)
这是最简单、最可靠,且在所有环境下都兼容的方法。只需在 ID 前加上一个有意义的前缀(prefix)即可。
### 第1章. 前言 {#ch-1}
### 第1节. 概述 {#sec-1-summary}
无论是 ch
(chapter)、sec
(section)还是 h
(header),任何字母前缀都可以。这样,在使用 CSS 或 JavaScript 引用该 ID 时,就绝不会遇到任何问题。
方法二:直接使用 HTML (最可靠的解决方案)
在某些特殊情况下,您可能“必须使用 id="1-section"
”。虽然用 Markdown 语法无法实现,但 Markdown 的一大优点就是可以与 HTML 混合使用。
只需将需要指定 ID 的部分直接写成 HTML 标签,就可以完全绕过解析器的限制。
<h3 id="1-section">第1章. 前言</h3>
这是能 100% 保证您得到想要 ID 的最可靠的解决方案。
结论:核心摘要
- 在 Markdown 中,像
{#1-my-id}
这样手动指定以数字开头的 ID 之所以会失效,是解析器为了保证与 CSS 的兼容性而设置的安全机制。 - 解析器自动生成的 ID(如
### 1. 标题
的情况)因其可被内部系统控制,所以可以以数字开头。 - 最佳解决方案是始终使用字母前缀,例如
{#ch-1}
。 - 如果必须使用以数字开头的 ID,请对该部分直接使用 HTML 标签。
现在您已经了解了 Markdown ID 的秘密,再也不用担心链接失效,可以更自由地构建您的文档结构了。