Skip to content

你不知道的 Markdown 知识

目前很多 Markdown 语法说明只介绍了 Markdown 具体语法的使用,而这里会介绍一些普通教程提及不多的知识。所以,在阅读之前,你应该掌握最基础的 Markdown 语法。

Markdown 的组成与结构

组成 Markdown 正文的元素可以分成区块元素行内元素

简单说,区块元素主要用来定义内容、提供框架,如标题、列表、段落等。而行内元素主要提供实质内容,如图片、文字等。

就好比一个表格(区块元素),我们需要文字、图片(行内元素)来填充它。

我们可以将一份 Markdown 文档看成一系列连续的区块元素(包括段落、区块引用、列表、分割线、区块代码等)的纵向排列,部分区块(如引用和列表)可以包含其他区块,而其他区块(如标题和段落)则包含行内元素,如文本、图片、链接、行内代码等等。

commonmark - https://commonmark.org

段落、文本行、换行

段落与行的概念在 Markdown 中虽然很基础,但是很重要。可惜很多 Markdown 教程都将其忽略。

一个文本行指连续两个换行之间的内容,并非指最终显示所看到的行。简单说,手动换行才叫一行,自动换行形成的不叫一行

段落由一个或多个连续文本行组成,两个段落由空行分开

当一个段落需要包含多个文本行时,需要现在行末敲入两个或以上空格再回车。不过很多编辑器可以直接回车换行。

知道这些有什么用?就可以用来调整文档的疏密。段落间的间距比较宽,如果希望文档密一点,多使用强制换行;如果希望文档优雅整齐一点,可以多用段落。

区块元素的相接

前面说过,一份 Markdown 文档看成一系列连续的区块元素的纵向排列。所以一份 Markdown 文档的结构基本是由区块元素决定的,而区块元素之间的关系有两种——首尾相接和嵌套。

原生的 Markdown 只规定了段落间需要空行,没有规定其他的区块如何相接。我们往往会想当然的认为其他区块直接相接就可以了。但是真的是这样吗?

其实,不同区块间有不同的规则,不同的编辑器也有不同的规则,这是几乎所有编辑器的共有现象。所有,区块相接存在这严重的“方言”。但是,它们也有一些规则是通用的:

  • 有明确开始标识和明确结束标识的区块可不用空行。当我们回头看原生 Markdown 语法设计的时候,会发现虽然 Markdown 也是一种轻量级的标记语言,可是基本所有区块元素只有开始标识(比如引用使用 > 开始,序列表使用 *+- 开始),却没有结束标识,这种区块的结束就取决于下一个区块或空行,不同的编辑器会产生不同的结果。但是后来加入的部分语法开始使用包裹式的标识,比如区块公式使用 $$ 包裹,这些区块就有着明确的结束标识。当像这样有着明确开始和结束表示的区块相接时,一般编辑器都不会出现差异,所以可以不用空行,直接换行相接。

  • 分隔线与标题后接区块可以不空行。分隔线与标题占用的行数比较固定,只有一行或两行,其后可以直接换行接任何区块元素。

  • 区块引用和列表后接其他区块必须空行。区块引用和列表与其他区块不同,它们可以嵌套区块,而且有 Lazy 输入(懒人输入,回车直接沿用上方样式),所以必须用空行区分。

  • 使用减号画分隔线时,前面必须预留一空行。因为连续三个 - 的语法与 Setext 式标题语法重合了,不留空行容易造成识别错误。如果不想使用预留空行,也可以在减号内加空格,如 - - -,以避免语法重合。

区块元素的嵌套

区块元素中引用和列表可以实现区块的嵌套,我们将其称为可嵌套区块。当我们说嵌套的时候,并非只指自身的嵌套,而是说可以嵌套基本所有类型的区块。

引用的嵌套

引用的嵌套相对简单,只要所有的嵌套内容每行行首加上 > 即可,多级嵌套就多加几个 >

md
> 段落 1 行 1
> 段落 1 行 2
>
> ---
> 段落 2
>
> > 二级引用

上述代码的效果如下:

段落 1 行 1 段落 1 行 2


段落 2

二级引用

引用的嵌套在实际写作中不太使用,一般只会用到简单的文段易用,嵌套最多用到段落。而且,目前很多编辑器的引用嵌套都有个不起眼的小 bug,嵌套中的标题会被纳入到目录大纲。

列表的嵌套

列表的嵌套相对复杂,目前一般有两种方式来实现,一是 Tab 方式,二是对齐方式。

Tab 方式是原生 Markdown 提出的嵌套方式,使用 4 个空格或 1 个 Tab 缩进实现多级嵌套(这里的 Tab 指 4 个空格,有的编辑器 Tab 键值不一样,或者会根据上一行变化)。

对齐方式是 CommonMark 提倡的方式,不固定每次嵌套所需的空格数量,使用空格缩进至嵌套内容与列表项目首行对齐为止。

两种方式各有优势,Tab 方式更易写,每次缩进按一个 Tab 键即可;对齐方式更易读,写出来的文档与最后显示的结果更接近。

范围元素的嵌套

在原生 Markdown 中将所有的行内元素叫做范围元素。但是这里的范围元素指行内元素中采用标识包裹的语法元素,包括强调、重强调、删除线和行内代码。如删除线内嵌套强调:~~123**456**789~~。需要注意的是:

  • 行内代码可以被嵌套,但是不能嵌套其他范围元素;
  • 强调、重强调和删除线不支持与自身嵌套,只能嵌套不同的范围元素。

转义

Markdown 之所以易写易读,很大程度的功劳在于它使用了大量的常见符号来构建语法,但是如果需要写入被占用的这些特殊符号,就会面临特殊符号被误识别为 Markdown 语法的可能性。

这时候就需要对特殊符号进行转义,转义方式为在符号前添加一个反斜线 \。比如,想输入:

2017. 金鸡报喜!

就需要在 Markdown 中写成 2017\. 金鸡报喜!,否则会被识别为有序列表。

下面是 John Gruber 提供的符号列表,这些符号常常需要被转义(当然不限于这些符号):

符号中文名英文名
\反斜线backslash
`反引号backtick
*星号asterisk
_下划线underscore
{ }大括号 / 花括号curly braces
[ ]中括号 / 方括号square brackets
( )小括号 / 括弧parentheses
#井号hash mask
+加号plus sign
-减号 / 连字符minus sign / hyphen
.英文句号 / 小数点dot
!感叹号exclamation mark

输入 Markdown 代码

如果想用区块代码记录 Markdown 围栏式区块代码怎么办?想在行内代码中添加反引号 ` 怎么办?

我们知道无论围栏式区块代码还是行内代码,输入的内容都会原样输出,直到结束的反引号出现,如果代码包含反引号,就可能被错误识别,提前结束代码。代码内部也不支持转义,上一节中提到的转义技巧无法使用。

这是,可以用更大的围栏包围代码来解决,如用 4 个反引号:

md
````
```
围栏式代码
```
````

那么,行内代码怎么添加反引号呢?行内代码也不能使用反斜线转义,无论 ```` ` ` 都不能得到想要的结果。

同样,这是可以使用类似上面的方法。如果行内代码内添加一个反引号,就用两个反引号包裹,如果要添加连续的反引号,就用三个反引号包裹,以此类推。

这是一个反引号的写法:`` ` ``。这是两个反引号的写法:``` `` ```

如果代码存在多个反引号但不连续,用两个反引号包裹:``行内代码用`反引号`包裹``

兼容 HTML

非程序员可能不知道,Markdown 兼容 HTML 语法。这就能解释为什么有的人用 < > 包裹内容的时候会发现内容消失了,因为它被当做 HTML 标签识别了。如果要显示尖括号,需要对其进行转义。

虽然 Markdown 兼容 HTML,但是在 Markdown 文档中使用 HTML 标签显然不符合 Markdown 设计的本意,而且懂 HTML 的人也不多,所以在书写 Markdown 文档时,HTML 标签是不推荐使用的。