前置知识: Markdown

Markdown 列表语法

7 min入门

无序/有序/任务列表语法、嵌套缩进规则、起始序号控制与列表内嵌块级元素的细节。

知识点地图

  • 知识类别:列表语法——无序/有序/任务三种列表及其嵌套、内嵌块级元素与边界行为。本篇是列表主题的唯一专篇(原引用篇中的列表章节已归并至此)。
  • 解决什么问题:并列信息怎么写;嵌套层级怎么不塌;有序列表的起始序号控制;列表里放代码/引用/段落。
  • 什么时候用到:README 的安装步骤(有序)、特性清单(无序)、待办(任务);文档里几乎每三段就有一个列表。

认知导入(Layer 0 生存层) 前置知识:003 段落与换行。 边界说明:列表是”并列信息”的默认表达。本篇的核心难点只有一个——缩进决定层级;其余都是三种列表的排列组合。 强制练习:分别用 - 和 1. 写三行列表;把第二行缩进两个空格,观察它如何变成子项。

1. 无序列表

1.1 语法

-、*、+ 加一个空格开头,三种标记渲染效果完全一致。团队内统一用一种(推荐 -,输入最快且不会被斜体语法干扰):

markdown
- 无序列表项 1
- 无序列表项 2
- 无序列表项 3

标记后必须有空格:-列表项 不是列表,是普通文本。

1.2 多行内容与续行

列表项内容太长需要换行时,续行缩进到与首行文本对齐(懒延续也允许不缩进,但对齐写法更可靠、更易读):

markdown
- 这是一个很长的列表项,
  换行后与首行文本对齐,
  仍然属于同一个列表项
- 另一个列表项

1.3 松散与紧凑

项与项之间加空行会形成”松散列表”,渲染时行距更大(每项包裹在段落里);不加空行则是紧凑列表。两种都合法,同一文档保持一种风格——markdownlint 的 MD032 规则可以帮团队强制统一。

2. 有序列表

2.1 语法

数字 + 英文句号 + 空格 开头:

markdown
1. 第一项
2. 第二项
3. 第三项

2.2 序号规则:首项决定起始值

这是有序列表最容易被讲错的规则,分两层:

  • 第一项的数字决定列表从几开始:写 3. a\n4. b 会渲染成从 3 开始的列表(用于在长文档中续接编号);
  • 后续项的数字不影响显示:全部写 1. 也能渲染出递增序号,渲染序号自动连续。
markdown
3. 从三开始
4. 自动递增为四
5. 自动递增为五

实践建议:源码按真实顺序书写(1. 2. 3.),既保证起始值正确,也让 diff 与阅读友好。

2.3 有序列表也能嵌套

子项缩进到父项内容列(1. 占 3 列,缩进 3 空格):

markdown
1. 一级项
   1. 二级项
   2. 二级项
2. 另一个一级项

3. 任务列表

任务列表是 GFM 扩展:在列表项开头加 [ ](未完成)或 [x](已完成,大小写均可):

markdown
- [ ] 未完成的待办任务
- [x] 已完成的待办任务
  - [ ] 可嵌套的子任务

识别条件严格:标记必须是列表项内容的开头、方括号内只能有空格或 x、标记后必须有空格。GitHub/GitLab 上复选框可点击勾选并写回源码。详细语义、交互行为与渲染器差异见 markdown/170-TaskList。

4. 嵌套列表与缩进规则(本篇重点)

4.1 缩进的本质:对齐父项内容列

CommonMark 的判定标准是”子列表缩进到父项内容的起始列”,不是全局固定值:

markdown
- 无序父项
  - 二级项(缩进 2 空格,对齐"无"字)
    - 三级项(再缩进 2 空格)

1. 有序父项
   - 二级项(缩进 3 空格,对齐"有"字)

10. 两位数父项
    - 二级项(缩进 4 空格)

两条硬性边界:

  • 缩进不足(少于父项内容列):子项被解析为父项的同级,层级塌掉——这是嵌套列表翻车的第一名;
  • 缩进过头(相对内容列达到 4 空格):内容被解析为缩进式代码块,出现奇怪的缩进代码。

因此”嵌套列表必须缩进 4 空格”是一个流传很广的误解:对 - 项它反而逼近代码块阈值,正确做法是最小对齐缩进(无序 2 空格、有序 3 空格)。

4.2 制表符风险

CommonMark 把制表符按”跳到下一个 4 列倍数”展开,理论上一个制表符等价 4 空格;但不同编辑器对 Tab 的显示宽度不同,混用空格与制表符是层级错乱的常见根源。列表缩进只用空格,并在编辑器里开启”Tab 转空格”。

4.3 不同类型混合嵌套

无序与有序可以互相嵌套:

markdown
- 无序列表项
  1. 内部有序第一步
  2. 内部有序第二步
- 无序列表项

4.4 层级深度建议

渲染层面没有硬性上限,但三层以上读者就难以追踪归属,超过三层应考虑拆分列表或改用小标题。

5. 列表项内嵌块级元素

列表项可以承载段落、代码块、引用等块级元素,关键是整体缩进到父项内容列。

5.1 嵌入代码块(推荐围栏式)

markdown
- 列表项 1

  ```python
  print("Hello, World!")
  ```

- 列表项 2

代码块缩进 2 空格(与 - 项的内容列对齐)即可识别为项内代码块;缩进式代码块则要求相对内容列再加 4 空格,容易出错,优先用围栏式。

5.2 嵌入引用

markdown
- 列表项 1
  > 这是列表项内的引用
  > 可以跨多行
- 列表项 2

5.3 嵌入链接与图片

行内元素直接写即可:

markdown
- [Markdown 指南](https://www.markdownguide.org)
- 本地图片:![截图](./images/step-1.png)

图片路径建议使用仓库内相对路径而非外部占位图服务(外链图床容易失效)。

5.4 嵌入段落

空行 + 缩进:

markdown
- 列表项 1

  这是列表项内的一个段落,可以写详细说明。

- 列表项 2

6. 列表与段落的边界行为

CommonMark 规定:列表可以打断段落(无序列表、以及首项为 1 的有序列表可以直接跟在段落文字后一行开始);首项不是 1 的有序列表不能打断段落。这在”正文后直接写列表”时通常无害,但当你写的是以连字符开头的一行普通文字(如日期 - 2026-01-01 事件)时,可能意外变成列表——必要时用转义 \- 或前置空行处理。

7. 常见问题排查

现象原因解决
列表显示为普通文本标记后缺空格- 列表项(减号后加空格)
嵌套项与父项同级缩进少于内容列无序 2 空格、有序 3 空格
子项变成代码块缩进达到内容列 +4 空格减少缩进到对齐即可
有序列表从 2 或 3 开始首项数字不是 1起始序号由首项数字决定
任务没有复选框渲染器不支持 GFM 或标记写法错误核对 [ ] 与空格;换 GFM 渲染器
列表项间距忽大忽小紧凑/松散混用项间统一不加空行
有序列表项内换行被切成新段落1. 项的续行未缩进续行缩进 3 空格(对齐内容列)

小结

  • 初学者要点:无序用 - 、有序用 1. ,标记后加空格;嵌套缩进”无序 2 空格、有序 3 空格”;列表里放代码块用围栏式并保持缩进。
  • 进阶注意:缩进的本质是对齐父项内容列,4 空格是代码块阈值不是列表标准;有序列表的起始值由首项数字决定、后续数字被忽略;任务列表是 GFM 扩展(详见 markdown/170-TaskList);列表可打断段落,首项非 1 的有序列表除外;缩进只用空格不用制表符。

动手实践

练习 1(缩进边界实验):写一个无序嵌套列表,子项分别缩进 1、2、5 空格各试一次,观察 1 空格塌成同级、2 空格正常、5 空格变代码块的三种结果。

提示:判定标准是「对齐父项内容列」(- 为 2),不是固定 4 空格。

练习 2(起始序号续接):写一个 1-5 的有序列表,中间插入一段说明文字,然后用 6. 作为下一项首数字续接列表,验证渲染序号连续。

提示:续接项的首数字决定起始值;后续数字随便写。

练习 3(列表内嵌代码):在列表项内放一段代码(分别用围栏式与缩进式),验证围栏式只需对齐内容列、缩进式要求内容列 +4。

提示:工程结论是永远用围栏式——缩进式的 6 空格要求一碰就碎。

参考实现(先自己动手,再看这里)
markdown
<!-- 练习 1 -->
- 父项
 - 一空格:塌成同级
  - 两空格:正确子项
       - 五空格:内容列(2)+4 = 代码块阈值,渲染为代码

<!-- 练习 2 -->
1. 安装依赖
2. 修改配置

> 中间可以插说明文字

6. 启动服务        <!-- 渲染为 3.(首项数字 6 不生效,因为列表未断) -->
<!-- 注意:若列表被空行+非缩进内容真正打断,6. 会从 6 开始——这正是 §2.2 的规则 -->

<!-- 练习 3 -->
- 项目一

  ```js
  console.log("fenced")   // 围栏式:缩进 2 格即可
  • 项目二

    plaintext
    console.log("indented")  // 缩进式:需 6 格
plaintext

</details>