目前很多Markdown语法说明只介绍了Markdown具体语法的使用,而本文主会介绍一些普通教程里提及不多的知识。所以,在阅读之前,你应该掌握最基础的Markdown语法。
组成Markdown正文的元素可以分成区块元素和行内元素。
简单说,区块元素主要用来定义内容、提供框架,如标题、列表、段落等。而行内元素主要提供实质内容,如图片、文字等。
就好比一个表格(区块元素),我们需要用文字、图片(行内元素)来填充它。
我们可以将一份Markdown文档看成一系列连续的区块元素(包括段落、区块引用、列表、标题、分割线、区块代码等)的纵向排列,部分区块(如引用和列表)可以包含其他区块,而其他的区块(如标题和段落)则包含行内元素,如文本、链接、图片、行内代码等等。
——翻译自 commonmark.org
段落与行的概念在Markdown中虽然很基础,但是很重要。可惜很多Markdown的教程(特别是国内教程)都将其忽略。
一个文本行指连续两个换行之间的内容,并非指最终显示所看到的行。简单说,手动换行才叫一行,自动换行形成的不叫一行。
段落由一个或多个连续文本行组成,两个段落间由空行分开。
当一个段落需要包含该多个文本行时,需要先在行末敲入两个或以上空格再回车。不过目前很多编辑器可以直接敲回车换行。
知道这些有什么用?可以用来调整文档的疏密。段落间的间距比较宽,如果希望文档密一点,多使用强制换行;如果希望文档优雅整齐一点,可以多用段落。
前面说过,一份Markdown文档看成一系列连续的区块元素的纵向排列。所以一份Markdown文档的结构基本是由区块元素决定的。而区块元素之间的关系有两种——首尾相接与嵌套。
原生的Markdown只规定了段落间需要空行,没有规定其他的区块如何相接。我们往往会想当然的认为其他区块直接换行相接就可以了。但是真的是这样吗?
其实,不同区块间有不同的规则,不同的编辑器也有不同的相接规则。这是几乎所有编辑器共有的现象。所以,区块相接存在着严重的方言问题。
但是,它们也有一些规则是通用的:
>
开始,无序列表使用*
、+
或-
开始),却没有结束标识,这种区块的结束就取决于下一个区块或空行,不同的编辑器或产生不同的结果。但是后来加入的部分语法开始使用包裹式的标识,比如区块公式使用$$
包裹,这些区块就有着明确的结束标识。当像这样有着明确开始标识和结束标识的区块相接时,一般编辑器都不会出现差异,所以可以不用空行,直接换行相接。-
画分割线时,前面必须预留一空行。因为连续三个减号—
这个语法与Setex式标题(底线式标题)语法重合了,不留空行容易造成识别错误。如果不想使用预留空行,也可以在减号内加空格,如- - -
,以避免与Setex标题语法重合。
的使用。这个标签其实很少会用到,一般只在带lazy输入的区块连续出现的时候用于分割区块。目前允许lazy输入的区块有:区块引用、缩进式代码、列表。空白HTML标签不会再最后的输出中显示,所以用来写备注也是可以的。区块元素中引用和列表可以实现区块的嵌套,我们将其称为可嵌套区块。
当我们说嵌套的时候,并非只指自身的嵌套,而是说可以嵌套基本所有类型的区块。
引用的嵌套相对简单,只要所有的嵌套内容每行行首加上>
,跟写简单的文字引用一样,只不过每一行都加>
而已,多级嵌套就多加几个>
。
示例:
> 段落1行1
> 段落2行2
>
> ---
> 段落2
>
> > 二级引用
效果:
段落1行1
段落2行2
段落2
二级引用
引用的嵌套,在实际写作中不太实用,一般只会用到简单的文段引用,嵌套最多用到段落。而且,目前很多编辑器的引用嵌套都有个不起眼的小bug,嵌套中的标题会被纳入到目录大纲。
列表的嵌套相对复杂,目前一般有两种方式来实现,一是Tab方式,二是对齐方式。
Tab方式是原生Markdown提出的嵌套方式,使用4个空格或1个Tab缩进实现多级嵌套(这里的Tab指4个空格,有的编辑器Tab键值不一样,或者会根据上一行变化)。
对齐方式是CommonMark提倡的方式,不固定每次嵌套所需的空格数量,使用空格缩进至嵌套内容与列表项目首行对齐为止。
两种方式各有优势,Tab方式更易写,每次缩进按一个Tab就可以;对齐方式更易读,写出来的文档与最后显示的结果更接近。
在原生Markdown中将所有的行内元素叫做范围元素。但是这里的范围元素指行内元素中采用标识包裹的语法元素,包括强调、重强调、删除线和行内代码。
如删除线内嵌套强调:123**56**789
注意:
Markdown之所以易写易读,很大程度的功劳在于它使用了大量的常见符号来构建语法,但是如果需要写入被占用的这些特殊符号,就会面临特殊符号被误识别为Markdown语法的可能性。
这时候就需要对特殊符号进行转义,转义方式为在符号前添加一个反斜线\
。
比如想输入:
2017. 金鸡报喜!
就需要在Markdown中这么写,否则会被识别为有序列表:
2017\. 金鸡报喜!
下面是John Gruber提供的符号列表,这些符号常常需要被转义(当然不限于这些符号):
符号 | 中文名 | 英文名 |
---|---|---|
\ | 反斜线 | backslash |
` | 反引号 | backtick |
* | 星号 | asterisk |
_ | 下划线 | underscore |
{ } | 大括号/花括号 | curly braces |
[ ] | 中括号/方括号 | square brackets |
( ) | 小括号/括弧 | parentheses |
# | 井号 | hash mark |
+ | 加号 | plus sign |
- | 减号/连字符 | minus sign/hyphen |
. | 英文句号/小数点 | dot |
! | 感叹号 | exclamation mark |
如果我们想用区块代码记录Markdown围栏式区块代码怎么办?想在行内代码中添加反引号`
怎么办?
我们知道无论围栏式区块代码还是行内代码,输入的内容都会原样输出,直到结束的反引号出现,如果代码内包含反引号,就可能被错误识别,提前结束代码。代码内部也不支持转移,上一节中提到的转移技巧无法使用。
这时,可以用更大的围栏包围代码来解决,如用4个反引号`
:
````
```
围栏式代码
```
````
那么,行内代码内怎么添加反引号呢?行内代码也不能使用反斜线转义,无论```
或` ` `
都不能得到想要的结果。
同样,这时可以使用类似上面的方法。如果行内代码内添加一个反引号,就用两个反引号包裹,如果要添加连续的反引号,就用三个反引号包裹,以此类推。
这是一个反引号的写法:`` ` ``
。
这是两个连续反引号的写法:``` `` ```
。
如果代码存在多个反引号,但不连续,用两个反引号包裹:`` 行内代码用`反引号`包裹 ``
。
非程序员可能不知道,Markdown兼容HTML标签语法。这就能解释为什么有的人用尖括号< >
包裹内容得时候会发现内容消失了,因为它被当做HTML标签识别了。这时候对尖括号转义即可。
虽然Markdown兼容HTML,但是在Markdown文档中使用HTML标签显然不符合Markdown设计的本意,而且懂HTML的人也不多,所以在书写Markdown文档时,HTML标签是不推荐使用的。