Skip to content

第六章 Markdown 语法差异 ​

学过核心语法和几种常见扩展后,很容易碰到一个问题:为什么有些写法在 GitHub 能显示,换个软件却不行?

先看任务列表:

md
- [x] 已完成任务
- [ ] 未完成任务

有的工具会显示复选框,有的只把它当作普通文本。

公式也一样:

md
$$
E = mc^2
$$

支持数学渲染的编辑器会排出公式;不支持的环境里,你看到的可能还是原样的标记:

text
$$
E = mc^2
$$

这不是文件坏了。Markdown 的实现一直不止一种,工具也会按自己的需要增加扩展。先把它看成“共同基础 + 按需扩展”会比较好理解:

text
Markdown
   │
   ├── 原始 Markdown:奠定基础写法
   ├── CommonMark:明确核心解析规则
   │   └── GFM:在 CommonMark 基础上加入 GitHub 常用扩展
   └── 工具扩展:按各自需要加入,不一定以 GFM 为基础

下面先分清这些规则从哪来,再拿同一份文件对照两个平台的显示结果。

Markdown 语法差异成因与方言演进全景

6.1 差异来源 ​

Markdown 方言成因:解析歧义机理与场景驱动分化

原始 Markdown ​

Markdown 起初想做的事很直接:让人用容易读的纯文本写内容,再转换成 HTML。

例如:

md
# Python

Python 是一种编程语言。

- 简单
- 易学
- 生态丰富

这种文本不用转换成 HTML 也能直接读懂,这是 Markdown 一开始就很看重的设计目标。不过早期 Markdown 更像“一套语法说明加一个参考实现”,不像正式标准那样把每种边界情况都定义得很细。

例如:

text
列表缩进几个空格?
空行如何处理?
HTML 和 Markdown 混合时怎么解析?
嵌套列表如何判断?

不同开发者写解析器时,可能会做出不同选择:

text
解析器 A
↓
一种行为

解析器 B
↓
另一种行为

方言差异就这样慢慢出现了。

基础语法

先看最早的 Markdown 解决了哪些基础需求,这也能帮助理解后面的 CommonMark 和 GFM:

text
标题
段落
强调
列表
链接
图片
引用
代码
分隔线

例如:

md
# 标题

这是一段正文。

**重要内容**

- Python
- Java

[官网](https://example.com)

> 引用内容

这些语法构成了 Markdown 的基本形态,直到今天仍是最常用的一部分。

解析歧义

原始 Markdown 的麻烦不只是功能少,更在于有些细节没有定义清楚。普通写作者未必会留意,但解析器开发者必须决定这些情况该怎么处理:

假设有一段复杂文本:

text
列表
  缩进
代码块
空行
HTML

规则不够精确,不同实现就可能把同一段内容转换成不同的 HTML:

text
同一个 .md 文件
        ↓
解析器 A
        ↓
结果 A

同一个 .md 文件
        ↓
解析器 B
        ↓
结果 B

这就是 Markdown 兼容性出现问题的原因之一。

方言成因 ​

Markdown 的“方言”可以类比不同地区的表达习惯:大家都懂基础写法,平台却会加上自己的说法和功能。比如:

md
# 标题
md
- 列表
md
[链接](https://example.com)

不同平台还可能增加:

text
表格
任务列表
删除线
数学公式
双向链接
流程图
提示块

这些分支合在一起,就形成了不同的 Markdown 方言:

text
共同基础
   ↓
Markdown 核心语法
   ↓
不同平台继续扩展
   ↓
不同 Markdown 方言

差异大致来自几方面。

早期规则

规范没说清的边界情况,不同开发者就可能各自判断。比如:

text
这种写法到底算列表还是普通文本?

解析器给出的结果也就可能不同。

平台需求

平台做什么,往往决定了它想给 Markdown 加什么。GitHub 常用于代码和项目协作:

text
代码
项目文档
Issue
Pull Request
text
任务列表
表格
代码
自动链接

知识管理软件更看重:

text
双向链接
页面嵌入
属性
标签

数学笔记工具则可能需要:

text
LaTeX
公式编号
数学环境

需求不同,扩展方向自然也不同。

扩展机制

Markdown 还很容易接入其他工具。代码块可以标注语言:

md
```python
print("Hello")
```

沿着这个做法,有些工具会把特定标记交给其他解析器处理,例如 Mermaid:

md
```mermaid
flowchart LR
A --> B
```

也就是说:

text
普通代码块
↓
增加特定语言标记
↓
由扩展工具继续处理

代码块本身还是 Markdown 的结构,标记后的内容则由扩展接手。

6.2 CommonMark ​

CommonMark:严格形式化规范与生态最大公约数基石

规则统一 ​

CommonMark 试着把 Markdown 的核心解析规则说得更清楚,让不同工具遇到同一段文本时,尽量按同一套方式处理。它没有重新发明 Markdown,而是明确了这些内容的行为:

  • 标题;
  • 列表;
  • 代码块;
  • 引用;
  • 链接;
  • HTML;
  • 转义。

解析价值

简单说,原始 Markdown 给出大致写法,CommonMark 则进一步规定遇到各种情况时该怎么解析:

text
原始 Markdown
↓
告诉你“大概应该怎么写”

CommonMark
↓
进一步明确“各种情况下到底应该怎么解析”

普通写作者在简单内容里未必看得出区别,比如:

md
# Python

- Flask
- FastAPI

这类写法通常到处都能正常显示。普通作者未必能明显感觉到 CommonMark 的存在,但它给解析器、编辑器和文档工具提供了更统一的参照。

规范边界 ​

可以把 Markdown 生态理解成:

text
Markdown 生态
├── CommonMark:核心解析规则
│   └── GFM:在其基础上扩展
└── 各工具:按需选用规则和扩展

CommonMark 关注的是 Markdown 基础部分如何稳定工作,并不打算包下所有工具功能。数学公式、Mermaid 和 Obsidian 双向链接都属于其他扩展:

text
数学公式
Mermaid
Obsidian 双向链接

6.3 GFM ​

GFM:CommonMark 超集继承与 4 大开发者协作扩展

语法扩展 ​

GFM 是 GitHub Flavored Markdown 的缩写,也就是 GitHub 风格的 Markdown。它以 CommonMark 为基础,增加表格、删除线、任务列表和自动链接等协作中常用的写法:

  • 表格;
  • 删除线;
  • 任务列表;
  • 自动链接。

开发协作需求

GitHub 不只是发布文章的地方,还承载代码托管、Issue、Pull Request 和项目协作:

text
代码托管
Issue
Pull Request
项目管理
开发者协作

所以项目 README 常要写功能对比、安装步骤和任务进度,Issue 里也会列待办:

text
功能对比表
安装步骤
任务进度
代码块
链接

Issue 中经常需要:

text
- [ ] 修复登录问题
- [ ] 增加测试
- [x] 更新文档

表格

例如:

md
| 框架 | 语言 |
| --- | --- |
| FastAPI | Python |
| Vue | JavaScript |

表格现在很常见,但它是后来加入并普及的扩展,不属于最早的核心语法。

任务列表

例如:

md
- [x] 创建项目
- [x] 编写 README
- [ ] 编写测试

任务列表在这些地方尤其顺手:

text
Issue
项目计划
检查清单

删除线

例如:

md
~~旧方案~~

可以标记已经废弃或不再采用的内容:

md
我们原本计划使用 ~~Flask~~,后来改成 FastAPI。

自动链接

在很多 GFM 环境里,直接输入网址就会被识别为链接:

text
https://github.com/

邮箱地址等文本也可能自动变成链接,写 Issue、README 和评论时会省几步。

规范关系 ​

关系可以这样看:

text
CommonMark
   ↓
提供基础 Markdown 规则
   ↓
GFM
   ↓
增加 GitHub 常用扩展

经常写下面这些内容的话,了解 GFM 会很有帮助:

text
README
开源文档
技术文章

常见支持范围

其他工具不一定完整实现 GFM,不过表格、删除线、任务列表和代码块已经相当常见:

text
表格
删除线
任务列表
代码块

掌握核心语法,再熟悉其中常见的几项,日常写作通常就够用了。

GFM 的定位

GFM 不是 Markdown 的“下一版”,也不是从 Markdown 1.0 升级到 GFM 2.0;它是建立在 CommonMark 上的一种常用方言:

text
Markdown 1.0
↓
GFM 2.0

上面这种版本升级关系并不准确,实际关系更接近:

text
Markdown
├── CommonMark
│   └── GFM
└── 软件按需增加的扩展

6.4 工具扩展 ​

除了 CommonMark 和 GFM,具体软件也会按自己的场景增加语法。

工具扩展:Markdown 万能宿主容器与领域扩展挂载体系

比如,知识管理软件可能支持:

text
双向链接
页面嵌入
属性
标签

文档网站工具则可能提供:

text
自定义容器
组件
Frontmatter
代码组

数学工具还可能加入:

text
LaTeX
数学环境

这些都超出了 Markdown 的通用核心。

平台语法 ​

Obsidian

Obsidian 用 Markdown 文件保存笔记,同时加上了不少知识管理功能。比如 [[Python]] 可以指向笔记:

md
[[Python]]

同样,[[FastAPI]] 会链接到名为 FastAPI 的笔记。这种双向链接在个人知识库里很方便,但它不是通用 Markdown;放到不支持它的工具里,可能只会看到原始字符:

text
[[FastAPI]]

嵌入语法

Obsidian 还可以用下面的写法嵌入其他笔记:

md
![[python.md]]

也能用来嵌入其他内容,例如:

text
图片
音频
PDF
其他内容

这对个人知识库很实用,也意味着文件会更依赖 Obsidian。要跨平台迁移时,记得检查这些写法。

VitePress

VitePress 用 Markdown 构建文档网站,因此还提供了不少面向技术文档的功能:

text
Frontmatter
代码高亮
自定义容器
Vue 组件
Markdown 插件

页面里甚至能直接写 Vue 组件,例如:

md
<MyDemo />

这已经超出传统 Markdown 核心,属于 VitePress 的 Markdown + Vue 文档体系。

Frontmatter

静态网站生成器常在 Markdown 顶部放一段 Frontmatter:

yaml
---
title: Markdown 入门
date: 2026-10-04
---

它用来保存页面元数据,例如:

text
标题
日期
作者
分类
标签
布局

Frontmatter 很常见,却不属于 Markdown 核心语法,通常由这些工具生态定义:

text
静态网站生成器
内容管理工具
文档框架

嵌入能力 ​

数学公式

例如:

md
$$
E = mc^2
$$

标记写在 Markdown 文件里,但公式内容由数学系统处理:

text
E = mc^2
text
Markdown
负责文档结构

LaTeX
负责数学表达

MathJax / KaTeX
负责公式渲染

换句话说,这是几种工具配合完成的效果,不是 Markdown 自己突然多出了完整的数学排版能力。

LaTeX 的定位

容易混淆的是把 Markdown、GFM 和 LaTeX 当成同一层的版本:

text
Markdown
GFM
LaTeX

它们其实不是并列关系:

text
Markdown
│
├── CommonMark:核心解析规则
│   └── GFM:增加 GitHub 常用语法
└── 工具扩展:由具体工具决定
    ├── 数学公式支持(嵌入部分 LaTeX 数学语法)
    ├── Mermaid 图表支持
    ├── Obsidian 语法
    └── VitePress 扩展

LaTeX 是独立的排版系统;Markdown 工具只是可能支持在文档里嵌入其中一部分数学语法。

Mermaid

例如:

md
```mermaid
flowchart LR
A --> B
```

Markdown 先把它识别成代码块,mermaid 标记再告诉支持它的工具把内容交给 Mermaid 解析器:

text
mermaid

处理过程大致是:

text
Markdown
↓
识别 mermaid 代码块
↓
Mermaid 解析器
↓
生成图表

所以 Mermaid 不是 Markdown 的另一个版本,而是借助代码块接入的图表扩展。

扩展边界 ​

统一语法很难包下所有功能,因为工具的用途并不一样。GitHub 需要:

text
Issue
任务列表
代码

Obsidian 更需要:

text
知识链接
嵌入
笔记关系

VitePress 则关注:

text
文档网站
组件
导航

学术工具可能更看重:

text
公式
引用
论文

如果全部塞进 Markdown:

text
Markdown
+
任务管理
+
知识图谱
+
数学排版
+
网页组件
+
数据库属性
+
图表

这样一来,Markdown 反而会失去简单这个特点。现实中的做法更像是:

text
一个稳定的基础
+
按需要增加扩展

6.5 兼容性核验 ​

跨平台兼容性核验:双端渲染断层对照与兼容三色梯

对照任务 ​

假设你在 Obsidian 里写笔记,现在准备把同一份文件发布到 GitHub。把下面内容保存为 compat_check.md,再在同目录新建一个只含 # Python 的 Python.md。发布时把两个文件一起放进仓库:

md
# FastAPI

## 安装

```bash
pip install fastapi
```

## 学习任务

- [x] 安装
- [ ] 路由
- [ ] 数据验证

## 公式

$$
E = mc^2
$$

## 相关笔记

[[Python]]

先不要改源码。分别在 Obsidian 的预览和 GitHub 的目标页面查看 compat_check.md,对照下面四项:

源码Obsidian 预览GitHub 页面核对点
# FastAPI 与代码块记录标题和代码是否成形记录标题和代码是否成形基础结构是否保留
- [x] 与 - [ ]记录是否出现任务框记录是否出现任务框扩展是否被识别
$$...$$记录公式或原始字符记录公式或原始字符数学渲染是否启用
[[Python]]记录链接或原始字符记录链接或原始字符目标平台是否识别内部链接

GitHub 上的显示还要看实际发布位置。以目标页面的预览为准;文件能打开,不代表里面的扩展都能正常显示。

再给每项写法标明来源:

text
# 标题
→ 核心 Markdown

代码块
→ 核心 Markdown

任务列表
→ 常见扩展 / GFM

数学公式
→ LaTeX 数学扩展

[[Python]]
→ Obsidian 扩展

如果 [[Python]] 在目标页面原样显示,而 Python 笔记也会随文档一起发布,可以把它改成普通链接:

md
[Python](./Python.md)

链接里的文件名和大小写要与目标仓库中的 Python.md 一致。

如果公式还是原样字符,先检查目标平台是否启用了数学渲染;不支持时,再按发布需要换成图片或普通文字。任务框没显示,也可以保留清单内容,或改成普通列表。每次调整一处,再回到两个页面核对。

这样就能看出哪些内容可以直接迁移,哪些扩展需要替换或降级。

差异判断 ​

排查显示差异时,先分清源码和渲染器。article.md 这样的 Markdown 文件只是文本;GitHub、Typora、Obsidian 和 VitePress 则负责解释它:

text
GitHub
Typora
Obsidian
VitePress

不同渲染器支持的扩展不同,所以:

text
同一个 Markdown 文件
+
不同 Markdown 渲染器
=
不同显示结果

平台专属语法

一个常见误会,是把某个软件的扩展当成通用语法。比如你习惯在 Obsidian 里写:

md
[[FastAPI]]

放到其他网站后,页面可能原样显示:

text
[[FastAPI]]

这不是文件坏了,而是目标工具不认识 Obsidian 的语法。再看自定义容器:

md
::: tip
注意事项
:::

某些文档工具能识别它,换到别的平台却未必。碰到看起来很特别的写法,先问一句:

这是通用 Markdown,还是当前工具自己的扩展?

语法识别

下面这些通常是最基础、最通用的写法:

text
#
##
**
*
-
1.
>
[]
![]
`

而看到这些标记时,就该留意它们可能依赖扩展:

text
[[]]
:::
$$
```mermaid
---
key: value

再确认目标工具是否支持。

显示差异

Markdown 保证的重点是内容结构,不是像 PDF 那样在所有软件里像素级一致。例如:

md
# Python

GitHub、Typora 和 VitePress 可能各用一套字体和样式,但都会把它认作一级标题。这种差异是正常的。

6.6 迁移策略 ​

跨平台迁移策略:成本天平与语法平替降级决策树

通用写法 ​

文档要同时放在 GitHub、Typora、Obsidian、VitePress 等地方时,优先用通用语法。

例如:

md
# FastAPI

## 安装

执行:

```bash
pip install fastapi
```

更多信息请查看 [FastAPI 官网](https://fastapi.tiangolo.com/)。

这种内容通常比较好迁移。至于双向链接、LaTeX、Mermaid、自定义容器等扩展,先确认目标平台是否支持:

text
双向链接
LaTeX
Mermaid
自定义容器

场景取舍 ​

大致来说,越靠近核心 Markdown,兼容性越高,但功能也越少;平台专属扩展能提供更多功能,跨平台时却更容易遇到差异:

text
越接近核心 Markdown
↓
兼容性越高
功能越少

而:

text
使用越多平台专属扩展
↓
功能越丰富
兼容性可能越低

例如:

text
标准链接
[FastAPI](fastapi.md)

兼容性通常很好。

而:

text
[[FastAPI]]

在 Obsidian 中更加方便,但跨平台能力会下降。

没有哪种写法总是最好,先想清楚文档最后要在哪儿用。

个人笔记

如果笔记只在 Obsidian 里用,放心写:

md
[[双向链接]]

双向链接等功能在个人库里很省事。如果文档确定只发布到 VitePress,也可以用它的自定义容器、组件和 Frontmatter:

text
自定义容器
组件
Frontmatter

真正容易出问题的是:现在依赖很多专属语法,之后又希望无成本地迁到别的平台。

公开内容

教程、开源文档、README、长期资料或多平台文章,通常更适合采用:

text
核心 Markdown
+
少量常见扩展

以后换工具时,迁移成本也会低一些:

text
GitHub
↓
VitePress
↓
其他平台

学习顺序 ​

刚开始不用同时记住所有方言,按这个顺序学就够了:先掌握核心语法,包括:

  • 标题;
  • 段落;
  • 强调;
  • 列表;
  • 链接;
  • 图片;
  • 引用;
  • 代码。

然后补上常见 GFM 能力:

  • 表格;
  • 删除线;
  • 任务列表;
  • 常见自动链接行为。

最后按使用的工具补扩展:Obsidian 的双向链接、嵌入和属性,VitePress 的 Frontmatter、代码组、自定义容器和 Vue 组件。写数学内容时再学 LaTeX,需要图表时再看 Mermaid。

6.7 本章小结 ​

Markdown 方言演进谱系与工程写作罗盘

text
Markdown
│
├── 核心思想
│   ├── 纯文本
│   ├── 标题
│   ├── 列表
│   ├── 链接
│   └── 代码
│
├── CommonMark:更严格地规范核心行为
│   └── GFM:在 CommonMark 基础上增加扩展
│       ├── 表格
│       ├── 删除线
│       ├── 任务列表
│       └── 自动链接等
│
└── 工具扩展
    ├── Obsidian
    │   └── 双向链接 / 嵌入
    ├── VitePress
    │   └── Frontmatter / 组件 / 文档扩展
    ├── 数学渲染
    │   └── 嵌入部分 LaTeX 数学语法
    └── Mermaid
        └── 图表
text
原始 Markdown:奠定基础写法
   ↓
CommonMark:明确核心解析规则
   ├── GFM:在其基础上增加 GitHub 常用语法
   └── 其他工具可按需增加扩展,不必经过 GFM

跨平台分享时优先用通用语法;文档只服务于一个工具时,也可以用它的专属功能。下一章会看看常用编辑器和平台各自支持什么,包括 VS Code、JetBrains、Typora、Obsidian、GitHub、VitePress 和 AI 工具。