Markdown 是一组纯文本标记语法,而不是只有一个渲染器、功能完全一致的单一语言。John Gruber 的原始设计强调可读源码和简单 HTML 输出;CommonMark 规定兼容核心,GitHub Flavored Markdown(GFM)、MDX、R Markdown 和各编辑器方言则增加不同能力。可靠的文档应声明方言、渲染器、扩展、消毒策略和目标输出。
核心要点
- 先学习 CommonMark,再核对目标平台方言。表格、任务列表、脚注、数学公式、Mermaid、原始 HTML 和 JSX 并非所有 Markdown 的核心能力。
- Markdown 源码不会自动变成安全 HTML。应对输出进行转义或消毒,限制 URL 协议、属性、嵌入内容和原始 HTML。
- HTML 与 Markdown 互转可能丢失结构、样式、元数据、空白或行为,应保留原始来源并测试往返。
- 使用语义标题、描述性链接、有意义的替代文本、可键盘操作的 HTML,避免依赖颜色或布局技巧传达信息。
- 代码围栏、表格对齐、脚注和换行依赖解析器细节,应使用生产环境的精确渲染器测试示例。
方言与兼容性
| 方言或扩展 | 它是什么 | 常见增加能力 |
|---|---|---|
| CommonMark | 规定核心语法和解析模型 | 标题、段落、强调、列表、链接、图片、引用、代码、分隔线 |
| GFM | GitHub 的扩展集合 | 表格、任务列表、删除线、自动链接和代码围栏行为 |
| MDX | Markdown 与 JSX/组件语法结合 | 需要受信任构建流水线的组件和表达式 |
| R Markdown | 加入可执行文档工具的 Markdown | 代码块、输出和可复现报告流程 |
| 数学/Mermaid 扩展 | 渲染器集成 | 公式或图表区块 |
“支持 Markdown”不足以说明兼容性,必须写出解析器和启用的扩展。GFM 能渲染的文档,在只支持 CommonMark 的解析器中可能只显示原始标点。
CommonMark 核心语法
标题与段落
ATX 标题使用一到六个 #,后跟空格:
## 二级标题
### 三级标题
Setext 标题使用下划线,只支持一、二级:
一级标题
===========
二级标题
-------
段落之间使用空行。段落中的单个换行在渲染后可能仍是空格;硬换行可在行尾使用两个空格或渲染器支持的反斜杠,显式 <br> 属于 HTML,可能被禁用或消毒。
标题层级应表达文档结构,而不是只为了获得更小字号。在宿主文档允许时保留一个有意义的页面主标题,不要只为视觉尺寸插入低级标题。
强调与行内代码
*斜体* 与 _斜体_
**粗体** 与 __粗体__
***粗斜体***
`行内代码`
\*字面星号\*
分隔符的行为会受标点和嵌套影响。命令、路径和标识符应使用反引号;代码本身包含反引号时使用更长的围栏。
列表与引用
- 第一个项目
- 第二个项目
- 嵌套项目
1. 第一步
2. 第二步
> 一段引用。
>
> > 嵌套引用。
有序列表的数字可能被渲染器规范化;如果读者会维护源码,应使用有意义的编号。保持缩进一致,并测试嵌套代码块。
链接与图片
[CommonMark 规范](https://spec.commonmark.org/)
[长引用链接][spec]
[spec]: https://spec.commonmark.org/ "CommonMark"

链接文字应描述目标,而不是“点击这里”。优先使用 https 并校验协议;除非有明确策略,否则拒绝 javascript:、意外的 data: 和不安全自定义协议。
图片替代文本应表达图片用途或重要信息。只有真正装饰性的图片才使用空 alt;图表、流程图或仅图片说明应提供文本替代。图片 URL 还可能涉及版权、留存和隐私审查。
分隔线
一行中的三个或更多相同 -、* 或 _ 可以形成分隔线:
---
不要用分隔线替代缺失的标题或语义段落。
代码、表格与脚注
围栏代码
使用带可选语言标签的围栏:
```python
print("hello")
```
标签只是高亮提示,不保证代码可编译,也不保证每个渲染器认识它。不要依赖颜色表达含义;代码应在无高亮时仍可读。伪代码应明确标注,要求可复现的命令或依赖应固定版本。
表格
很多平台把表格作为 GFM 扩展:
| 字段 | 含义 |
| :--- | :--- |
| `id` | 稳定标识符 |
| `name` | 展示名称 |
单元格中的字面管道符应转义或放进代码,表头要有意义;表格过宽或包含屏幕阅读器难以理解的重要关系时,应提供线性替代。不要只用表格做页面布局。
脚注
部分解析器支持脚注扩展:
一条证据说明[^source]。
[^source]: 写明来源和访问日期。
应检查生成的 ID、键盘导航、返回链接和本地化。目标渲染器不支持脚注时,改用普通链接或明确的参考资料区。
原始 HTML 与安全渲染
很多解析器会传递部分 HTML:
<details>
<summary>实现说明</summary>
内容仍受宿主 HTML 策略约束。
</details>
原始 HTML 不是安全边界。接受不可信 Markdown 的服务应使用明确的解析器,对生成 HTML 按允许列表消毒,移除事件处理属性和危险 URL,限制 iframe/img/svg 行为,并使用合适的 Content Security Policy。不要执行不可信文档中的脚本、JSX 或模板表达式。
align、内联样式和任意尺寸可能被忽略或删除。优先使用宿主应用拥有的语义 HTML 和 CSS。不要声称 Markdown 解析器本身能阻止 XSS。
数学公式、Mermaid 与其他扩展
$...$、$$...$$ 数学分隔符、Mermaid、语法高亮和自定义指令都是渲染器能力。应定义:
- 解析器和扩展版本;
- 公式是否转换为可访问 MathML,是否提供文本替代;
- 图表在服务端还是客户端渲染;
- 图表文字、链接和 SVG 输出是否消毒;
- 不支持扩展的读者和导出格式使用什么回退。
Mermaid 源码不自动等于图片,不应默认从不可信输入执行或渲染。图表不要只依赖颜色,应包含标签和文字说明。
转换边界
HTML 与 Markdown 的表达能力不同。转换可能丢失 CSS 选择器、ARIA 关系、嵌套结构、注释、ID、脚注、数学公式、交互行为和精确空白;HTML 还可能包含转换器必须移除的不安全元素。
更可靠的转换流程是:
- 确认来源信任级别并保留原始文件;
- 使用理解规范的库,而不是正则表达式;
- 明确映射标题、列表、链接、图片、表格和代码;
- 按目标上下文消毒输出;
- 用正常和畸形输入 fixture 渲染并比较;
- 记录解析器版本、选项、源哈希、输出哈希和复核结果。
Markdown 转 HTML 的输出仍需转义和消毒;HTML 转 Markdown 也不能证明语义或视觉等价。
无障碍与发布
- 使用逻辑标题层级和描述性链接。
- 为视觉内容提供 alt、图注、文字稿或数据表。
- 保持键盘焦点可见,确保折叠和控件无需鼠标也能操作。
- 不要只用颜色传达状态。
- 检查对比度、代码可读性、表格溢出、缩放/重排和减少动画行为。
- 保留语言元数据,使用能帮助读者和工具的代码标签。
Markdown 本身不能保证无障碍;渲染器、CSS、HTML 结构、内容和辅助技术路径都影响结果。
编写检查清单
- 声明目标方言和渲染器。
- 需要移植时优先使用核心语法。
- 在目标环境测试链接、图片、代码围栏、表格、脚注和扩展。
- 发布不可信 Markdown 前先校验并消毒。
- 保留源文件、许可证、图片权利和转换元数据。
- 在 CI 中执行链接、无障碍和渲染输出检查。
- 审查导出 HTML 的脚本、URL、ARIA 结构和折叠行为。
常见问题
Markdown 有统一标准吗?
没有一个覆盖所有实现的 Markdown 语言。CommonMark 规定核心,GFM 和其他工具增加扩展。需要兼容时应写明方言和渲染器。
Markdown 文件渲染安全吗?
不会自动安全。原始 HTML、URL、图片、SVG、扩展和生成 HTML 都可能带来安全或隐私风险,应根据目标上下文解析和消毒。
Markdown 与 HTML 可以无损互转吗?
通常不能。交互行为、样式、元数据、空白、脚注、公式和无障碍关系都可能丢失。应限制转换子集、测试并保留事实来源。
围栏代码的语言标签会执行代码吗?
不会,通常只是高亮提示。但构建系统或 notebook 扩展可能增加执行行为,必须检查流水线后再把文档当作代码。
为什么表格或脚注在一个站点有效,在另一个站点无效?
这些功能属于扩展,或解析器规则不同。应检查目标方言、插件、版本和生成的 HTML。
一手来源
- CommonMark 规范
- GitHub Flavored Markdown 规范
- MDN:HTML Sanitizer API
- W3C Web Content Accessibility Guidelines (WCAG) 2.2
- OWASP:Cross Site Scripting Prevention Cheat Sheet
总结
Markdown 的价值在于源码可移植、可检查,而不是所有渲染器行为相同。应选择并记录方言,让语义优先于装饰,消毒不可信输出,保留无障碍信息,并用实际发布流水线测试转换。这样速查表才不会变成兼容性或安全陷阱。