Skip to content

块级元素:段落、标题、引用、列表、代码、分隔线

基于 CommonMark 0.31.2 / GFM · 核于 2026-07

速查

  • 段落:一或多行文本,段与段之间用空行分隔。段内单个换行是软换行(多被当空格);硬换行<br>)需行尾两个及以上空格或行尾一个 \
  • ATX 标题#~###### 表示 1-6 级;开头 # 后必须跟空格/制表符或行尾,否则不成标题(#标题 会变普通段落);可选闭合 #;最多 3 空格缩进,4 空格变代码块。
  • Setext 标题:文字下一行用 =(一级)或 -(二级)下划线,只有两级;下划线长度任意。⚠️ --- 紧贴上一行文字时优先当二级标题而非分隔线。
  • 块引用:行首 >(后跟一空格);>> 嵌套;是容器块,内部可放标题/列表/代码等其它块级元素。
  • 列表:无序标记 -/*/+(同一列表别混用);有序 数字.数字)起始编号看首项、后续数字被忽略并自动递增;嵌套靠缩进对齐。
  • 松紧列表(高频坑):项之间出现空行 → loose(松散) → 每项内容被 <p> 包裹、行距变大;无空行 → tight(紧凑) → 不加 <p>
  • 围栏代码块:3+ 个反引号 ``` 或 3+ 个波浪号 ~~~,上下围栏须同种字符;起始行 info string 第一个词按约定标注语言(供高亮)。
  • 缩进代码块:每行缩进至少 4 空格(或 1 Tab);不能中断段落(前面需空行),也无法标语言——实践中多改用围栏码。
  • 分隔线:单独一行、3 个及以上相同-/*/_;混用字符(-*-)不成立;最佳实践前后留空行。

一、段落与硬换行

段落是最基础的叶子块:一行或连续多行文本,段与段之间用空行分隔。这里最容易踩的是「换行」语义:

  • 软换行(soft break):段落内一个普通换行。多数渲染器把它折叠成一个空格,输出仍在同一行文本流内,不产生 <br>
  • 硬换行(hard break):要真正的行内换行,有两种标准触发——行尾放两个及以上空格,或行尾放一个反斜杠 \。二者都渲染为 <br>
  • 分段:要另起一个段落,需要一个空行
md
第一行末尾有两个空格 → 硬换行  
第二行(与上一行同段但换行)

这是新的一段(上面有空行)。

行尾两空格「肉眼不可见」是新手最常漏的坑,很多编辑器还会自动裁剪行尾空格;因此不少人更偏爱行尾 \ 或干脆用空行分段。

二、标题:ATX vs Setext

Markdown 有两套标题语法:

ATX 标题(最常用)用行首 # 的数量表示级别,1 到 6 级:

md
# 一级
## 二级
###### 六级

CommonMark 有一条硬性规则:开头的 # 序列后必须跟空格/制表符或行尾。所以 #标题(无空格)不构成标题,会被当普通段落原样输出——最佳实践是「# 后永远加一个空格」。ATX 还允许可选的闭合 #(如 ## 标题 ##,纯装饰)。

Setext 标题用「下一行下划线」的方式,只有两级:

md
一级标题
========

二级标题
--------

= 是一级、- 是二级,下划线长度任意。它的局限很明显——只能表达一、二级,三级及以上只能用 ATX。还有个陷阱:一段普通文字紧接着一行 ---,会被优先解析成 Setext 二级标题而不是分隔线,所以写分隔线时务必前后留空行。

三、块引用

块引用在每行行首加 >(后跟一空格)。它是容器块,内部可以嵌套其它块级元素——标题、列表、代码块,乃至用 >> 嵌套的更深引用:

md
> 一级引用
>
> > 嵌套引用
>
> - 引用里的列表项
> - 第二项
>
> ```js
> // 引用里的代码块
> const x = 1;
> ```

四、列表:有序、无序、嵌套、松紧

无序列表-*+ 任一(三者语义相同,但同一列表内不宜混用,否则会被拆成多个列表):

md
- 项 A
- 项 B

有序列表用「数字 + .(或 ))」。一条重要规则:起始编号由第一项决定,后续项的具体数字被忽略、只按顺序自增。所以全写 1. 会渲染成 1、2、3……;首项写 3. 则从 3 起数:

md
1. 第一(全写 1. 也会自动递增)
1. 第二
1. 第三

嵌套靠缩进对齐子项(一般 2 或 4 空格,与父项标记后的文字起点对齐最稳)。

松紧列表(tight vs loose)——高频坑

这是「列表莫名变稀疏」的根因。判定规则:只要任意两个列表项之间出现空行(或列表项内部由空行分隔的多个块),整个列表就变成松散列表(loose),此时每一项的内容都会被 <p> 标签包裹,视觉上行距明显变大;反之项与项紧挨、无空行则是紧凑列表(tight),不加 <p>

md
<!-- 紧凑:项内容不被 <p> 包裹 -->
- A
- B

<!-- 松散:项间有空行,每项被 <p> 包裹、间距变大 -->
- A

- B

想要紧凑的观感却发现列表被撑开时,第一反应就应该是「检查项与项之间是不是多了空行」。

五、代码块:缩进码 vs 围栏码

缩进代码块是最古老的写法:每行缩进至少 4 个空格(或 1 个制表符)。它有两个短板——无法标注语言(不能语法高亮),且不能中断一个段落(若上一行是段落文字、下一行直接缩进 4 空格,这行会被当作该段落的软换行延续,而非新代码块),要生效前面必须有空行。

围栏代码块(fenced)是如今的首选:用连续 3 个及以上反引号 ``` 或 3 个波浪号 ~~~ 作上下围栏(上下须同种字符,不能混用)。围栏码不需要每行缩进,还能在起始行紧跟一个 info string,其第一个词按约定表示语言,驱动语法高亮:

md
```python
def hello():
    print("hi")
```

要在 Markdown 里展示围栏语法本身(像上面这样),可以用更长的外层围栏(4 个反引号或 ~~~)把内层的三反引号包起来。

六、分隔线(thematic break)

分隔线是单独一行、3 个及以上相同字符 -*_ 组成,字符间可有空格:

md
---
***
___

混用不同字符(如 -*-)不构成分隔线。再次提醒那个交叉陷阱:--- 紧贴上一行文字会被当成 Setext 二级标题,所以分隔线前后请留空行。


块级骨架搭好后,进入 行内元素与 HTML 安全:强调、链接(行内/引用/自动)、图片、代码跨度、转义、原始 HTML 内嵌与安全。