Markdown:怎么用,以及为什么用

你可能不是第一次听说 Markdown 了。

所见即所得,从富文本编辑器说起

以前,人们在互联网上写作或发言喜欢使用「富文本编辑器」来实现充分自由的格式化。一般而言,富文本编辑器所做的事情就是把你输入的普通文本加上格式,形成对应的 HTML 编码。

拿我们喜爱的 QQ 空间日志编辑器来说,当我们选中「Markdown」,点击「B」按钮后,字体就会变粗。这个过程可以通过点击「HTML」来看到真相:

事实上,这个编辑器所做的一切,就是给「Markdown」这个单词加上了对应的 html 标签。

<div>你可能不是第一次听说 <span style="font-weight:bold">Markdown </span>了。<br/>
</div>

这件事情现在逐渐被 Markdown 取代。当你需要使用加粗效果的时候,你甚至不用挪开手去动鼠标。看一下在 CSDN 编辑器中的表现:

在「Markdown」的两侧,各加上两个星号 * 就可以实现「加粗」的效果:

你可能不是第一次听说 **Markdown** 了。

而这件事情的本质,其实和富文本编辑器的做法是一致的。Markdown 解析器会把这几个星号的标记识别成 <strong> 的 html 标签:

你可能不是第一次听说 <strong>Markdown</strong> 了。

是的,这是非常重要的一点。Markdown 的使命是让人更方便地写出符合 HTML 格式的文本,同时让人更加容易地阅读。

轻松的上手指南

既然 Markdown 最终通过解析器转换成 HTML 格式的文本,那么它的语法必然可以和 HTML 标签对应。

值得注意的是,在写 Markdown 时,一定不要吝啬回车键。对大多数解析器而言,两个不同的段落之间需要 至少两个回车才能正确解析出换行,而多个回车最终也只会解析成为一次换行。

粗体和斜体

用来表示强调的「粗体」和「斜体」,分别使用两个星号和一个星号包围:

这是**粗体***斜体*

转换成 HTML 就是:

这是<strong>粗体</strong><em>斜体</em>

显示的效果大概是:

标题

使用标题时,可以使用不同数量的井号 #,分别代表多层级的标题样式:

# 大标题

## 中标题

### 小标题

转换成 HTML 后,会形成 <h1><h2><h3> 的标签。

显示的效果如下:

引用

引用的样式在不同的编辑器和网站上显示差异较大。Github 上显示的效果为:

也有地方是这样显示的:

无论怎样呈现,它在 Markdown 中永远是使用一个大于号 >

> 引用了一段名人名言。

代码

代码分为行内代码和代码块,都是使用键盘上 ESC 下面那个按键上的符号 ` 来表示:

在一行中嵌入了 `int a;` 代码,还可以写一段:

```c
int a;
a = 10;
a++;
printf("%d\n", a);
```

大多数代码块都会自动带上代码高亮。具体的语言可以在代码块中指定,如上例中,我指定了 c 作为高亮的语言。

在 Github 中,它是这样显示的:

链接和图片

链接和图片长得挺像的。

[这个是链接](http://www.baidu.com/)

下面这个是图片:

![这样就是图片](http://y.gtimg.cn/music/photo_new/T002R300x300M000000C4fZU14IubU_1.jpg)

对应的 HTML 编码是:

<p><a href="http://www.baidu.com/">这个是链接</a></p>
<p>下面这个是图片:</p>
<p><img src="http://y.gtimg.cn/music/photo_new/T002R300x300M000000C4fZU14IubU_1.jpg" alt="这样就是图片"></p>

下面就显示了一个链接和一张图片:

列表

列表分为有序列表和无序列表,也就是 html 中的 <ol><ul> 标签:

- aa
- bb
- bb.1
- bb.2
- cc

1. aa
2. bb
3. cc

显示如下:

给你的文字加点结构

掌握前面所说的这些基本用法之后,我们就可以开始使用 Markdown 来写作了。如果你还对每一种标记的用法有所担心,不妨先写下纯粹的文本,回过头来再尝试添加这些 Markdown 标记。

  1. 使用 ## 添加标题之后,整个文章的骨架和结构就展现出来了。一般我只使用二级和三级标题,再往下划分的话,文章结构会过于复杂,并不利于阅读了。
  2. 对文中的关键词加上 ** 粗体标记。我个人比较偏爱粗体,而很少使用斜体。不过加星号这个动作总是破坏我的写作流畅性,但是在引导阅读方面,粗体的确是个好工具。
  3. 如果你的文章内有代码内容,或者文件路径,甚至只是快捷键,你都可以把它用 ` 标记形成行内代码。现在行内代码有一种滥用的趋势,因为很多时候,行内代码呈现出非常醒目的样式,所以很多人也用它作为强调的一种方式。
  4. 为你文字中的引用部分加上 > 标记。大部分 Markdown 编辑器都会把它做一个缩进,用上不同的字体、颜色或字号,并在段落前面加上一个竖线或者大大的引号。
  5. 适时地添加一些引用和代码块,会提升读者的阅读趣味。尤其在阅读疲惫的时候,醒目的引用样式和带背景色的行内代码通常会在读者速读的时候吸引到注意力。
  6. 链接和图片大概是在写作过程中自然而然会去添加的内容了。在 Markdown 中添加链接和图片时,方括号在前,圆括号在后,方括号中填文字,圆括号里写链接。
  7. 有序列表(也就是带数字编号的列表)和无序列表(通常使用实心和空心的圆点)都可以多层嵌套,这在文章结构中也是非常重要的工具。

可以看到,Markdown 非常有助于为文章构筑更加稳固的结构,合理运用 Markdown 标记也可以提升读者的阅读体验,引导读者的阅读重心。

只关注内容本身,无需操心样式

那么,我们写好了文章,并给我们的文章赋予了清晰的结构,接下来,如何呈现给读者呢?难道要让读者看复杂的 Markdown 标记,还是直接读更加复杂的 HTML 语言?

秉承着 HTML 和 CSS 之间「内容和样式分离」的主要思想,Markdown 只不过控制了「内容」的部分,而呈现出来的「样式」,实际是由对应的 CSS 文件来控制的。

在有的编辑器中,这个 CSS 文件可以自主配置,称为「主题」。除了 CSS 文件,一个主题通常还包括了在排版中用到的字体和图片。

也由于文章本身一般不携带任何样式信息,这给 Markdown 文件的「可移植性」带来了极大的便利。你只管写,根本不用考虑你会把它发表到 Github、CSDN 还是自己搭建的 Hexo 博客。

写完后,把它放到对应的文档或者博客编辑器中预览,最终呈现出来的样子由编辑器决定。而当你需要换个地方发表,你直接把源文件复制粘贴过去就行,而不用过多考虑样式。

不同编辑器的细微差异

在尝试过多个 Markdown 编辑器之后,你一定会发现,抛开由 CSS 决定的「样式」不说,不同的编辑器其实对同一个 Markdown 标记也可能出现不同的解析结果。

标题,还是正文

比如,我设计这样一段 Markdown 文本:

#这是一篇有关 Markdown 的笔记
不过很有趣。
##给你轻松的上手指南

注意到,我在 # 符号之后紧跟了标题内容,而没有使用空格隔开。

当我在 Mac 上的 MarkEditor 中输入时,它会把标题解析出来:

而 Typora 显然没有这样处理,这些文本全部作为了正文处理:

引用了一句,还是一段话

同样的,如果使用下面这段 Markdown 文本:

> 曾经沧海难为水
除却巫山不是云

有的解析器会把两句话都视为引用,而有的解析器只会把第一句话视为引用,第二句话则处理成了常规文本。

讲讲历史

这样的差异是有其历史原因的。2004 年,John Gruber 发明了 Markdown,不过他当时的实现非常简单,没有丰富的格式,也没有十分明确的规范。

在 Markdown 推广过程中,大家根据自己需要添加了许多元素。于是,我们有了表格(使用 Markdown 画表格实在非人类),有了待办事项(- [x]),甚至有了流程图(PlantUML)和数学公式(MathJax)。

对于原始版本的 Markdown 中没有讲明白的细节,这十多年里出现的解析器也根据各自的理解而进行了不同的处理。而由于大家对 Markdown 理解各不相同,因此有了不同的规范。

GFM:极具参考性的标准

在实际写作 Markdown 的过程中,我建议参照 Github 的 Markdown 标准,也就是 GFM。它以 CommonMark 为基础,并添加了些许扩展。

如果我们讨论「规范的 Markdown 语法」,那么 GFM 一定极具参考性。要知道,Github 可能是 Markdown 使用最多的地方了,几乎每个项目都有至少一篇使用 Markdown 写的 README.md 吧。

看看 GFM 的处理

回到前面有关标题的问题,查看 GFM 中 ATX heading 部分可以看到:

At least one space is required between the # characters and the heading’s contents, unless the heading is empty.

井号和标题内容之间至少要有一个空格,不然下面的情况就会被误判成标题:

#5 bolt

对于前面提到的引用问题,GFM 中有一个「懒惰条款」,在引用时可以省略第二行开始的 > 符号。

格式的精确控制

曾经沧海难为水,除却巫山不是云。

谜一样的富文本编辑器

如果你写过微信公众号,那你很可能会对它的后台编辑器深恶痛绝。不支持 Markdown 标记,甚至不支持 HTML 源码编辑,每一次调整格式都会带来不可预测的结果。

比如,如果我在下面的「当然」之前按一下退格键(),再敲一下回车键,它会变成怎样的格式呢?你准确地猜对了这一行为吗?

回到前面 QQ 空间的例子,如果我想要在「Markdown」后面输入文字,那么新输入的文字是跟前面的格式一样粗体呢,还是跟后面的格式一样常规字体?

至于 Microsoft Word……我相信你用了那么多年 Word 之后,在排版和格式方面一定有非常多想吐槽的地方,尤其是面对从网上复制粘贴过来的图文、使用其他版本 Word 编辑过的文件时,也一定有过非常多困惑甚至毫无头绪的时候。

Markdown 的表现

前面 QQ 空间中那种很「迷」甚至非常「薛定谔」的粗体操作,在 Markdown 中就可以精确地控制。

如果格式是这样的:

你可能不是第一次听说 **Markdown** 了。

显然,如果你在第二组 ** 输入文字,那么它就是粗体,如果你在第二组 ** 输入文字,那么它就是常规字体。

轻量级的思维导图

前面提到,Markdown 有助于给文章提供清晰的结构。而这,其实也可以帮助我们理清思路、记录思绪,起到类似「思维导图」的效果。——当然,如果你非要说思维导图是用来做读书笔记的,那么 Markdown 做读书笔记同样不逊色。

我一般使用两种方式来体现层级结构:

  • 多级标题
  • 多级列表

在记录只言片语的时候,我偏爱列表。由于可以直接通过「缩进」来控制层级,这几乎完全不会打断我的思考过程。并且在阅读时,缩进的格式也很容易可以被我的大脑转化成不同的层级。

而在会产生大段文本的时候,我会使用多级标题的形式,那就是一个小文章了。使用大标题作为思维导图的中心结点,各级标题依次作为子结点开枝散叶。

你也可以结合两者,在标题之下使用有序或者无序列表作为更细化的小结点。

# 解决一个问题

问题描述

## 第一种方案

1. 第一步
2. 第二步
3. 第三步

## 第二种方案

方案具体说明

与之对应的思维导图可能是这样的:

无论使用标题还是列表样式,最终你都可以通过工具实现 Markdown 和思维导图之间的互相转换。我习惯于使用 XMind ZEN 这个出色而简洁的思维导图工具来完成这一工作。

至于后续调整思维导图「样式」、给思维导图添加图标来帮助记忆和理解,这样一些事情就可以在写完「内容」之后再来完成。

得益于 Markdown 无需关心样式,而只需要关心内容本身的良好特性,做笔记显得特别轻松,而且我们对最终的效果也会有很强的信任感。

同样得益于 Markdown 简洁、清晰的标记语法,即便你最后并不需要把它转成思维导图,直接写作和阅读 Markdown 文本,使用时依然可以轻松达到轻量级的思维导图效果。

多样的阅读和编辑工具

当你想要写一个 Word 文档,你肯定会需要安装 Microsoft Word 或者金山 WPS 才行,而这两个软件甚至还不是完全免费的。

即便只是打开、阅读别人发过来的 Word 文件,你也需要安装动辄数百 M 甚至数 G 的 Office 套件。更恼人的是,如果 撰写这个文件的 Word 版本和你安装的不一致,甚至你看到的效果和作者那边的会有很大不同。

如果你转而使用 Markdown 来写作,那么情况会好很多。作为纯粹的文本文件,Markdown 文档可以使用任意一个文本编辑器来打开。与 Word 之类的字处理工具相比,文本编辑器不但体积小巧,而且兼容性强。

比如,你可以直接使用 Windows 上的记事本来编辑 Markdown 文件。由于 Markdown 本身的标记并不复杂,在大部分情况下,完全可以直接阅读和修改所谓「源码」。

试想下面的情景,如果不使用 Markdown,将会是怎样的混乱和麻烦:

  1. 你发给别人一个文件,那个人不懂 Markdown,但是他依然可以看懂、修改这个文件,并发回给你。即使有格式上的错误,你也很容易发现和调整
  2. 借用 别人的电脑,你总能找到一个可以打开、编辑 Markdown 文件的工具,无论是 Windows 的记事本、macOS 的文本编辑,还是 Linux 下的 Vi
  3. 通过网络传输时,如果 不能传送文件,那么 Markdown 完全可以直接把文本内容发过去,而不用担心格式的丢失
  4. 每个人可以使用自己偏好的编辑器修改和阅读同一个 Markdown 文件,即使 使用不同工具编辑,只要格式规范,就可以在其他人的编辑器中完美呈现

当然 Markdown 写作环境并不总是那么简陋。除了这些基础款的编辑工具外,你还可以使用 Typora 之类专门为 Markdown 设计的编辑器。这些工具在使用时更像是 Word 一样的字处理工具,但是最后保存的却是 Markdown 纯文本文件。

我个人使用 VSCode 进行 Markdown 的写作和阅读。虽然 Markdown 算不上 VSCode 的主要功能,但是依然表现出色。它会高亮显示标题、粗体,也支持自动填写链接和序号。与 Typora 相比,它更易于控制。与记事本相比,它提供了些许辅助。

毕竟,当我阅读或者写下一个「标题」时,我并不需要它真的变粗变大,而只要前面有个 # 符号,我就可以把它脑补成一个标题。同样的,当我看到 - 形成的无序列表,我根本不在乎它有没有最终显示成一个小圆点,事实上 小短横和小圆点对我的视觉来说也没什么显著的差别

当我们需要分享 Markdown 文件时,可以导出成为 HTML 网页,对方使用浏览器即可打开阅读。你也可以选择导出成 Word、PDF 或者图片。

由于 Markdown 最终是解析成 HTML 的,它顺理成章地成为了互联网上写作的最好格式之一。你可以直接把你的 Markdown 文件使用 Github Gist 发布,也可以使用 Hexodocsify 等工具十分高效地转换成自己的个人网站。

和版本控制工具的完美融合

要是你使用 Git、SVN 或者其他版本控制工具来管理你的文档,那么 Markdown 一定是你的首选。

文件大小

首先我们分别用 Word 和 Markdown 分别构建两个文件,Markdown 内容是:

## 一个故事

1. 开始
2. 进展
3. 结局

Word 内容是:

查看文件属性发现,他们的文件大小分别是 15339 字节和 51 字节。

由此可见,使用 Word 会使得文件变得更大。更大的文件意味着在版本控制时需要占用更多的存储空间,也意味着在传输过程中会消耗更多时间。

差异比对

接下来,我们修改这个文件,把第二点「进展」加粗,并把第三点「结局」改成「结尾」。以 git diff 为例查看修改了什么:

diff --git a/Markdown.docx b/Markdown.docx
index d3766a0..49d5293 100644
Binary files a/Markdown.docx and b/Markdown.docx differ
diff --git a/Markdown.md b/Markdown.md
index ba66675..34ca8dd 100644
--- a/Markdown.md
+++ b/Markdown.md
@@ -1,5 +1,5 @@
# 一个故事

1. 开始
-2. 进展
-3. 结局
+2. **进展**
+3. 结尾

可以看到,对于 Markdown 文本,git diff 完美展现出了两处修改。而 Word 文档却被直接视为二进制文件,并不能看到修改的内容。

如果借用知名对比工具 Beyond Compare,在 Word 中的这个变化也只能显示出「结局」改为了「结尾」,而对加粗的操作无能为力。

当文档内容更加复杂时,使用 Word 显然完全无法胜任版本控制系统的差异比对。而这,是版本控制的基础,我们完全无法明确得知 Word 文件在每一次提交中分别进行了什么修改。

更复杂的格式,也能全部应付

当你用了一段时间的 Markdown,可能你会发现,简单的标题、粗体这些格式,无法满足你在特定类型文档中的需求。我这里列举几个你可能用得上的不常用功能。

表格

在 Markdown 中手动插入表格是非常反人类的,不过表格用得挺多,还是要了解一下:

学号 | 姓名 | 成绩
--- | --- | ---
1 | AAA | 100
2 | BBB | 98
3 | CCC | 59

效果:

多段落的列表项

如何在一个有序列表中插入一个引用,又保持列表编号呢?只需要在引用前面加空格缩进就行,添加图片也是一样。

1. 第一条
2. 第二条
> 第二条很重要。
1. 第三条

效果:

添加的空格数量的规则是,在「第二条」三个字之前有多少字符,就在 > 前添加几个空格。

分割线

要插入一个分割线 <hr />,新起一行输入 *** 就可以了:

a
***
bbb

效果:

转义

如果不希望把 * 识别成列表,或者不希望把 > 识别成引用,直接在前面加上反斜杠 \

\> 我不再是引用。

效果:

待办事项

待办事项可以是已勾选的,也可以是未勾选的:

- [x] 已经做完的事情
- [ ] 还没做的事情

效果:

UML 图表

借助 PlantUML 可以直接在 Markdown 中绘制时序图、用例图、甘特图等图表:

@startuml
Alice -> Bob: Authentication Request
Bob --> Alice: Authentication Response

Alice -> Bob: Another authentication Request
Alice <-- Bob: another authentication Response
@enduml

效果:

目录

要在 Markdown 文档中插入当前文档的目录,只需要写一行 [TOC] 就可以得到。

直接写 HTML 或者 JS

最后,也是最重要的,由于 Markdown 本质上是 HTML 的一种别名,那么在 Markdown 中直接书写 HTML 就成了非常自然的事情。

例如需要在 Markdown 中配置一段可折叠的文本,那么可以直接这样写:

一起来玩捉迷藏。

<details>
<summary>我在哪里?</summary>

> 被你发现了。

</details>

效果:

而要是想实现一些动态效果,你甚至可以直接写 JavaScript!当然这需要你有一定的前端编程能力,就不再展开了。