说实话,我见过太多开发者——不管是刚入行的还是写了几年代码的老手——在写 Markdown 列表的时候,还在跟缩进和标点符号较劲。尤其是当你需要写一个三层甚至四层的嵌套列表时,那种“到底是两个空格还是四个空格?”、“这个横杠后面要不要加空格?”、“哎呀,这一行怎么变成新列表了?”的崩溃感,真的会让人想砸键盘。
今天咱们不整那些虚头巴脑的理论,直接聊聊怎么用最舒服的方式搞定嵌套列表,顺便把那些让你头皮发麻的常见 Bug 一次性清理干净。
一、 为什么我们总是搞砸嵌套列表?
在动手之前,先搞清楚问题出在哪。Markdown 的列表解析其实挺“情绪化”的。它不像代码那样严谨,它更像是一个努力理解你意图的读者。如果你写得稍微有点歧义,它可能就读不懂了,或者读出了一堆你根本没想表达的意思。
最常见的误区有两个:
- 缩进迷思:很多人死记硬背“嵌套要缩进 4 个空格”,但其实标准的 GitHub Flavored Markdown (GFM) 和大多数现代渲染器,只需要 2 个空格 就能识别嵌套。用 4 个空格反而容易在视觉上把内容推得太远,阅读体验很差。
- 符号混乱:有序列表(1. 2. 3.)和无序列表(- * +)混用时,一旦嵌套层级变深,序号可能会突然跳变,或者变成无序样式,让人一脸懵。
别担心,记住下面这三个核心原则,基本能解决 90% 的问题。
二、 三步搞定:从入门到精通
第一步:掌握“最小缩进”原则
这是最重要的一点。嵌套层级的识别,靠的是相对缩进,而不是绝对空格数。
对于无序列表,一个横杠 - 加一个空格,就是一个列表项。如果你想把这个项里面的内容再分一层,只需要在下一行开头加 2 个空格,然后再写一个 - 即可。
看这个例子:
- 一级列表项 A
- 二级列表项 A-1
- 三级列表项 A-1-1
- 四级列表项 A-1-1-1
- 二级列表项 A-2
- 一级列表项 B
注意看,二级、三级、四级 前面的空格数都是 2 个,相对于上一级的 - 符号。你不需要数是不是正好对着上一级的第一个字符,只要保证同级嵌套的缩进量一致就行。
第二步:有序列表的“隐形序号”
有序列表有个很有趣的特性:你写什么序号,它显示什么序号,但渲染结果通常是从 1 开始的连续数字。
这意味着,你可以在嵌套的有序列表中随意写数字,只要格式对,渲染器都会自动帮你整理好。比如:
1. 首先做这件事
1. 子步骤 A
2. 子步骤 B
2. 然后做那件事
1. 另一个子步骤
上面这个写法,渲染出来通常是:
- 首先做这件事
- 子步骤 A
- 子步骤 B
- 然后做那件事
- 另一个子步骤
但是! 这里有个大坑。如果你在嵌套的有序列表里想插一个无序列表,一定要小心。
第三步:混合嵌套的“断绝”技巧
当你在有序列表里想插入一个无序列表,或者反之,最简单的方法是加一个空行,或者使用不同的符号并明确缩进。
举个例子,如果你在写一个教程,步骤是有序的,但每个步骤里的细节是无序的:
1. 准备材料
- 纸张
- 笔
- 胶水
2. 开始制作
- 折叠纸张
- 粘贴部件
这种写法非常清晰。渲染器会完美识别出 1. 和 2. 是同级,而 - 纸张 等属于 1. 的子项。
三、 常见 Bug 修复实战指南
哪怕你懂了规则,有时候渲染结果还是会让你怀疑人生。下面是几个最经典的“翻车现场”及修复方案。
Bug 1:列表突然中断,变成了普通段落
现象:你写得好好的,突然有一行没有缩进,结果后面的内容都变成了普通文本,列表断了。
错误示范:
- 项目 A
- 项目 B
项目 C
- 子项目 C-1
原因分析:Markdown 解析器认为 - 项目 B 之后的那个空行(或者紧接的 项目 C)打断了列表的连续性。一旦列表断开,后续的缩进就失去了上下文,变成了普通文本。
修复方法: 保持列表的连续性。如果必须插入一段文字,要么让文字不缩进但前后都有空行(明确表示这是段落),要么确保列表项紧挨着。
- 项目 A
- 项目 B
项目 C 的说明文字
- 子项目 C-1
或者,如果你想让 项目 C 依然属于列表,确保它也有 - 前缀,并且缩进正确:
- 项目 A
- 项目 B
- 项目 C
- 子项目 C-1
Bug 2:嵌套层级“错位”,所有子项都跑到了最外层
现象:你明明想嵌套两层,结果渲染出来所有项都是同一级。
错误示范:
- 一级
- 二级
- 三级
- 四级
原因分析:这在视觉上没问题,但在某些严格的解析器中,如果 - 二级 和 - 三级 之间的逻辑关系不明确,可能会出问题。更常见的情况是,你试图在有序列表中嵌套无序列表,但没有足够的缩进。
错误示范(有序嵌套无序,缩进不足):
1. 第一步
- 子步骤
2. 第二步
这里 - 子步骤 没有缩进,解析器会认为它是和 1. 同级的无序列表,从而打乱整个结构。
修复方法: 确保嵌套项比父项多缩进至少 2 个空格。
1. 第一步
- 子步骤
2. 第二步
Bug 3:有序列表的序号不连续或重置错误
现象:你以为渲染出来是 1, 2, 3,结果变成了 1, 1, 1 或者 1, 3, 5。
原因分析:这通常发生在嵌套的有序列表中,解析器为了保持层级清晰,有时会重置序号。或者,你在中间插入了无序列表,导致有序列表的计数被意外打断。
修复方法:
最稳妥的办法:在有序列表的嵌套层级中,尽量使用统一的序号格式。 如果你需要嵌套两个有序列表,确保它们的起始序号逻辑清晰。如果只是为了显示,其实可以用 1. 开始,让渲染器自动递增,不要手动干预中间的序号。
另外,不要在有序列表中间突然插入一个没有缩进的无序列表,这会导致后续有序列表的序号混乱。
1. 开始
- 无序项 1
- 无序项 2
2. 继续(这里渲染器通常会正确处理,但如果前面的无序列表缩进不对,就会出错)
确保 1. 和 2. 的缩进对齐,且中间的无序列表正确缩进在 1. 下面。
Bug 4:代码块在列表嵌套中“炸锅”
现象:列表里想插入一段代码,结果代码块破坏了列表的缩进,或者列表符号消失了。
错误示范:
- 执行命令
`npm install`
- 启动服务
原因分析:行内代码 通常没问题,但如果是多行代码块,缩进会变得非常复杂。
修复方法: 使用缩进代码块(4 个空格缩进)或者围栏代码块(”`)。对于嵌套在列表中的代码块,推荐用围栏代码块,并适当缩进。
- 执行命令
```bash
npm install
- 启动服务
”`
注意,围栏代码块本身不需要额外的缩进,但它所在的行需要保持列表的缩进层级。上面的写法中,```bash 前面有 2 个空格,这是为了让它被视为 - 执行命令 的子内容。
四、 给你的终极建议:善用工具
说实话,靠手搓来验证嵌套列表是否正确,效率太低了。我建议你养成两个习惯:
- 实时预览:无论你用 VS Code、Typora 还是 Obsidian,一定要开着实时预览。写完一段列表,马上看看渲染效果,不对就立刻改,不要等全篇写完再回头找 Bug。
- 使用 Linter:像
markdownlint这样的工具可以帮你检查 Markdown 的格式问题。虽然它不能 100% 预判渲染结果,但能帮你发现很多明显的缩进错误。
最后,记住一点:Markdown 的本质是“可读性”,而不是“精准控制”。如果你发现嵌套列表怎么写都别扭,那可能是你在这段内容里的逻辑结构本身就需要重新梳理一下。把内容拆分成小段落,用更清晰的标题层级来组织,往往比强行嵌套多层列表更有效。
别再跟横杠较劲了,去享受写作本身吧。
