Markdown 分割线(水平线)语法教程

写长文档的时候,在两个主题之间插一条分割线(horizontal rule),能让内容结构更清晰。Markdown 的分割线语法特别简单——三个字符就能搞定,但有几个小坑值得注意。

Markdown 分割线的基本语法

在 Markdown 里,分割线有三种写法,效果完全一样:

---

***

___

三种写法渲染出来的结果都是一条横贯页面宽度的水平线,对应的 HTML 标签是 <hr>

根据 CommonMark 规范,这三种写法也叫"主题分隔"(thematic break)。你用哪种都行,关键是至少要写三个字符,而且必须单独占一行

超过三个也行,比如 -----*******,效果不变。

三个短横线(最常用)

第一部分内容。

---

第二部分内容。

这是用得最多的写法。GitHub 上大约 92% 的 Markdown 文件都用 --- 来做分割线。

三个星号

第一部分内容。

***

第二部分内容。

星号写法有个好处:不会和标题语法冲突(后面会详细说)。如果你特别在意这一点,可以用星号代替短横线。星号之间加空格也行,* * * 是合法写法。

三个下划线

第一部分内容。

___

第二部分内容。

下划线是最少人用的写法,但同样有效,所有主流 Markdown 解析器都支持。

语法规则详解

虽然写法简单,但有几条规则必须遵守,不然分割线可能显示不出来,甚至变成别的东西。

必须单独占一行

分割线所在的那一行只能有分割线字符(前后可以有空格),不能有其他文字:

<!-- 正确 -->
一些文字

---

更多文字

<!-- 错误:同一行有其他文字 -->
--- 这不是分割线

前后要留空行

这一点特别重要。--- 在某些情况下会被解析器当作二级标题的下划线(Setext 风格标题),而不是分割线:

<!-- 这会变成 H2 标题,不是分割线! -->
一些文字
---

<!-- 这才是分割线 -->
一些文字

---

更多文字

我之前在写一个项目的 CHANGELOG 时就踩过这个坑——版本号下面紧跟着 ---,结果版本号变成了大标题,分割线反倒没了。解决办法很简单:在 --- 上面加一个空行。

不能混用不同字符

每一行的分割线只能用同一种字符,混着写是不行的:

<!-- 错误:混用了短横线和星号 -->
--*
-*-

<!-- 正确:只用一种字符 -->
---

至少三个字符

两个字符不够,必须三个或以上:

<!-- 错误:只有两个 -->
--

<!-- 正确:三个或更多 -->
---
-----

不同平台的渲染差异

虽然所有主流平台都支持这三种写法,但渲染出来的样式略有区别:

平台支持情况渲染样式
GitHub支持细灰色线,约 1px,上下有 24px 间距
GitLab支持细灰色线
Reddit支持细线
Stack Overflow支持细线
Notion支持可用 ---/divider 命令,转为原生分割线块
Obsidian支持跟随主题配色的细线
VS Code 预览支持浏览器默认 <hr> 样式
Typora支持细线,可通过 CSS 自定义
Discord不支持无分割线功能
Slack不支持无分割线功能

用 HTML <hr> 标签作为替代

如果 Markdown 的分割线语法不生效(比如某些特殊环境),可以直接用 HTML 的 <hr> 标签:

一些文字

<hr>

更多文字

大多数支持 Markdown 的平台也支持内联 HTML,所以 <hr> 基本都能用。效果和 Markdown 语法一样。

自定义分割线样式

Markdown 本身不支持样式定制,但如果你用的平台允许 HTML 和 CSS,可以通过几种方式来美化分割线。

行内样式

直接在 <hr> 标签上加 style 属性:

<hr style="border: 2px solid #333; width: 60%; margin: 2em auto;">

这会渲染出一条深灰色、宽度为页面 60%、居中的分割线。GitHub 和大部分静态站点生成器都支持这种写法。但 Obsidian 的实时预览和一些会过滤 HTML 的编辑器可能不支持。

全局 CSS

如果你有自己的站点或博客,最好在 CSS 里统一定义分割线样式,而不是每个地方都写行内样式:

hr {
  border: none;
  border-top: 2px dashed #ccc;
  margin: 2em 0;
}

这样 Markdown 里所有的 --- 都会自动应用这个样式。

markdown-it 自定义渲染

如果你用 Eleventy、VuePress 这类基于 markdown-it 的静态站点生成器,可以通过覆写渲染规则来完全自定义 <hr> 的输出。

const markdownIt = require("markdown-it")
const mdSetup = markdownIt()

mdSetup.renderer.rules.hr = (tokens, idx, options, env, self) => {
  return '<hr class="custom-divider" />'
}

这样所有 Markdown 里的分割线都会渲染成带 custom-divider 类名的 <hr> 标签,你可以用 CSS 随意美化它。

分割线的实际使用场景

分割线用对了地方能让文档更有条理,用多了反而显得乱。以下是一些适合用分割线的场景:


项目介绍和功能描述...

---

## 更新日志

### v2.0.0

- 新增了用户管理功能
- 修复了登录超时问题

---

### v1.0.0

- 初始版本发布
  • README 的章节之间:把安装说明和使用说明隔开
  • 更新日志的版本之间:每个版本条目前后用分割线
  • 正文和附录/脚注之间:区分主体内容和补充信息
  • 主题切换的地方:两个完全不相关的话题之间

对了,如果每两三个段落就插一条分割线,那说明你可能应该用标题来分节,而不是分割线。分割线适合用在标题不太合适、但又需要一个明显视觉间隔的地方。

三种写法该选哪个?

说实话,选哪个都行,一致性比具体选哪个更重要。我的建议是:

写法优点缺点推荐场景
---最常见,最直观不加空行会和标题冲突日常使用(记得加空行就行)
***不会和标题冲突较少人用担心标题冲突的团队规范
___同上更少人用个人偏好

我个人一直用 ---,只要记住上面加个空行就没事。如果你在给团队写编码规范,*** 是最安全的选择,因为它完全消除了和标题混淆的可能性。

常见问题

为什么我的 --- 变成了标题?

因为 --- 紧跟在文字下面时,会被解析为 Setext 风格的二级标题。在上面加一个空行就能解决。

两个短横线 -- 能做分割线吗?

不能。至少需要三个。两个短横线在某些解析器里是删除线或破折号,和分割线无关。

分割线能加颜色或改粗细吗?

纯 Markdown 不行。但如果你用的平台支持 HTML,可以用带样式的 <hr> 标签实现,或者在站点的 CSS 里统一修改。

分割线和空行有什么区别?

空行只是增加段落间距,分割线会渲染出一条可见的横线。如果你只需要段落间距,用空行就够了,不需要分割线。

Discord 和 Slack 为什么不支持分割线?

这两个平台的 Markdown 支持是有限的子集,它们没有实现 thematic break 语法。在 Discord 和 Slack 里,你只能用 emoji(比如 —————- - -)来模拟分割线的效果。

参考来源