如何使用 Markdown 撰写文档
本文介绍了如何使用 Markdown 来编写 MDN Web 文档项目中的文档。我们以 GitHub 风格的 Markdown(GFM)为基础,并添加了一些扩展来支持一些我们在 MDN 上需要而 GFM 仍不支持的东西。
基础:Github 风格的 Markdown
MDN Markdown 的基础是 Github 风格的 Markdown(GFM):https://github.github.com/gfm/。这意味着,对于本文中未指定的内容,你可以参考 GFM 规范。而 GFM 又是 CommonMark(https://spec.commonmark.org/)的超集。
链接
GFM 规范定义了两种基础的链接类型:
在 MDN 上,我们仅允许使用内联链接。
以下是 MDN 上正确的编写 GFM 链接的方式:
[马卡龙](https://zh.wikipedia.org/wiki/馬卡龍)虽然美味,但制作难度大。
以下是 MDN 上错误的编写链接的方式:
[马卡龙][马卡龙]虽然美味,但制作难度大。
[马卡龙]: https://zh.wikipedia.org/wiki/馬卡龍
然而在某些情况下,参考链接因其紧凑性更为合适。例如,缩小宽表可使其更易于审阅和编辑。
| 名称 | 特征 |
| -------------------- | -------------------------------------------------------------------- |
| [马卡龙][马卡龙] | 虽然美味,但制作难度大。为茶会增添的优雅气质,几乎胜过任何其他甜点。 |
| [意式脆饼][意式脆饼] | 酥脆且更易制作。 |
[马卡龙]: https://zh.wikipedia.org/wiki/馬卡龍
[意式脆饼]: https://zh.wikipedia.org/wiki/義式脆餅
在极少数需要使用参考链接的情况下,请确保它们紧接在使用它们的上下文之后。
示例代码块
在 GFM 和 CommonMark 中,你可以使用“围栏代码块”来标示 <pre> 块。围栏代码块的起始位置后可以添加“信息字符串”。代码示例的语言必须通过信息字符串的首个单词指定,该语言将用于为代码块提供语法高亮功能。支持以下单词:
- 编程语言
- JavaScript
js——JavaScriptts——TypeScriptjsx——React JSXtsx——React TSX
- 类 C 语言
c——C 语言cpp——C++cs——C#java——Java
- 其他
python——Pythonphp——PHPrust——Rustglsl——GLSL(OpenGL 着色器)sql——SeQueL 命令wasm——WebAssemblywebidl——Web 接口定义语言
- JavaScript
- 样式
css——CSSscss——Sass(SCSS)less——Less
- 标记语言
html——HTMLsvg——SVGxml——XMLmathml——MathMLmd——Markdownlatex——LaTeX
- 命令提示符
sh——Bash/Shellbatch——Batch(Windows Shell)ps——PowerShell
- 配置或数据文件
json——JSONini——INIyaml——YAMLtoml——TOMLsql——SQL 数据库ignore——Gitignore 文件apacheconf——Apache 配置nginx——NGINX 配置
- 模板
- 其他
plain——纯文本diff——Diff 文件http——HTTP 标头regex——正则表达式uri——URI 和 URL
例如:
```js
const greeting = "我会得到 JavaScript 语法高亮";
```
如果你希望高亮显示的语言未在上方列出,请使用 plain 标记代码块。也可以按照 GitHub 讨论提出的流程请求其他语言的高亮支持。
备注:请严格按照上述列表使用语言标识符。例如,javascript 是不被允许的,必须使用 js。
阻止 lint
你可以为任何语言标识符添加 -nolint 后缀:
```html-nolint
<p>
我不会被 lint。
</p>
```
类似这样的代码块将得到适当的语法高亮,而且会被运行实例系统识别,但会被 lint 工具或自动化的格式化工具(如 Prettier)所忽略。你应该使用此后缀来展示 lint 工具或格式化工具不应该修复的无效代码或替代的格式。
附加类(信息字符串)
GFM 支持信息字符串,它允许作者提供有关代码块的附加信息。在 MDN 上,信息字符串会被转换为类名。
作者可以使用以下提供的任意一个信息字符串:
example-good:将其标注为良好示例(可供参考)example-bad:将其标注为错误示例(应避免使用)hidden:不在网页中展示此代码块。代码仅用于运行实例。
例如:
```js example-good
const greeting = "这是一个良好示例";
```
```js example-bad
const greeting = "这是一个错误示例";
```
```js hidden
const greeting = "这是一个隐藏的问候";
```
它们将被渲染为:
const greeting = "这是一个良好示例";
const greeting = "这是一个错误示例";
讨论参考
此议题已被解决:
备注、警告和标注
作者可使用 GFM 提示语法对内容进行特别标注。一共有三种类型:备注、警告和标注。
备注:在支持 GFM 提示之前,MDN Web 文档曾采用专有语法支持提示功能,并将其称为“noteblocks”。MDN 不支持以下 GFM 提示:[!TIP]、[!CAUTION]、[!IMPORTANT]。GFM 不支持 [!CALLOUT]。
- 要添加备注,请创建一个 GFM 块引用,起始行为
[!NOTE]。 - 要添加警告,请创建一个 GFM 块引用,起始行为
[!WARNING]。 - 要添加标注,请创建一个 GFM 块引用,起始行为
[!CALLOUT]。
备注和警告将在输出中添加本地化的“备注:”或“警告:”,而标注不会。当你想要提供自定义标题时,标注会是一个不错的选择。
多行块引用由空的块引用生成,就像普通的段落一样。此外,没有空格的多行内容会像常规 Markdown 行一样被处理和连接。
块引用可以包含代码块和其他块级元素。
示例
备注
> [!NOTE]
> 这就是编写备注的方式。
>
> 它可以有好几行。
这将会产生以下 HTML:
<div class="notecard note">
<p><strong>备注:</strong>这就是编写备注的方式。</p>
<p>它可以有好几行。</p>
</div>
此 HTML 将渲染为高亮显示的框,例如:
备注:这就是编写备注的方式。
它可以有好几行。
警告
> [!WARNING]
> 这就是编写警告的方式。
>
> 它可以有好几段。
这将会产生以下 HTML:
<div class="notecard warning">
<p><strong>警告:</strong>这就是编写警告的方式。</p>
<p>它可以有好几段。</p>
</div>
此 HTML 将渲染为高亮显示的框,例如:
警告:这就是编写警告的方式。
它可以有好几段。
标注
> [!CALLOUT]
>
> **这就是编写标注的方式。**
>
> 它可以有好几段。
这将会产生以下 HTML:
<div class="callout">
<p><strong>这就是编写标注的方式。</strong></p>
<p>它可以有好几段。</p>
</div>
此 HTML 将渲染为高亮显示的框,例如:
这就是编写标注的方式。
它可以有好几段。
包含代码块的备注
这是一个包含代码块的例子。
> [!NOTE]
> 这是编写备注的方式。
>
> 它可以包含代码块。
>
> ```js
> const s = "我在代码块中";
> ```
>
> 就像这样。
这将会产生以下 HTML:
<div class="notecard note">
<p><strong>备注:</strong>这是编写备注的方式。</p>
<p>它可以包含代码块。</p>
<pre class="brush: js">const s = "我在代码块中";</pre>
<p>就像这样。</p>
</div>
HTML 将渲染为包含代码块的框:
备注:这是编写备注的方式。
它可以包含代码块。
const s = "我在代码块中";
就像这样。
讨论参考
定义列表
为了在 MDN 中创建定义列表,你需要编写一个 GFM 无序列表(<ul>)的修改形式。在这种形式中:
- GFM
<ul>包含任意数量的顶级 GFM<li>元素。 - 每一个顶级 GFM
<li>元素必须包含一个 GFM<ul>元素作为其最后一个元素。 - 最内层的
<ul>必须包含一个单独的 GFM<li>元素,其文本内容必须以“: ”(冒号后跟空格)为开头。这个元素可能包含块级元素:包括段落、代码块、嵌套的列表和备注。
每个顶级的 GFM <li> 元素会被转换为 <dt>/<dd> 对,如下:
- 顶级的 GFM
<li>元素会被解析成一个 GFM<li>元素,其内部的内容会组成<dt>中的内容,除了最内层的<ul>元素,它将不被包含在<dt>中。 - 最内层
<ui>中包含的<li>元素会被解析成一个 GFM<li>元素,其内部的内容会组成<dd>中的内容,除了开头的“: ”,它将被丢弃。
例如,这是一个 <dl>:
- term1
- : 对术语 1 的描述
- `term2`
- : 对术语 2 的描述
它可以包含多个段落,也可以包含代码块:
```js
const thing = 1;
```
在 GFM/CommonMark 中,这将会产生以下 HTML:
<ul>
<li>
<p>term1</p>
<ul>
<li>: 对术语 1 的描述</li>
</ul>
</li>
<li>
<p><code>term2</code></p>
<ul>
<li>
<p>: 对术语 2 的描述</p>
<p>它可以包含多个段落,也可以包含代码块:</p>
<pre>
<code class="brush: js">const thing = 1;</code>
</pre>
</li>
</ul>
</li>
</ul>
在 MDN,这将会产生以下 HTML:
<dl>
<dt>
<p>term1</p>
</dt>
<dd>对术语 1 的描述</dd>
<dt>
<p><code>term2</code></p>
</dt>
<dd>
<p>对术语 2 的描述</p>
<p>它可以包含多个段落,也可以包含代码块:</p>
<pre>
<code class="brush: js">const thing = 1;</code>
</pre>
</dd>
</dl>
使用此语法编写的定义列表必须由成对的 <dt>/<dd> 元素组成。且不能编写包含多个连续 <dt> 元素或多个连续 <dd> 元素的列表:解析器将其视为错误。我们希望这个限制适用于 MDN 上几乎所有的定义列表,而对于那些不被希望受此限制的,你可以回退到原生 HTML。
以下格式是不允许的:
- `param1`、`param2`、`param3`
- : 对 `param1` 的描述
- : 对 `param2` 的描述
- : 对 `param3` 的描述
如果你需要将多个 <dt> 元素关联到同一个 <dd> 上,可以考虑将它们以顿号(英文文档请使用半角逗号)分隔后提供给同一个 <dt> 元素,如下:
- `param1`、`param2`、`param3`
- : 对参数 1、2、3 的描述
这样设计语法的原因是:在使用 CommonMark(如 Prettier 或 Github 预览)工具的情况下,它相当容易编写和解析。
讨论参考
表格
GFM 提供了创建表格的语法,我们在 MDN 中使用了它。但是,有时 GFM 表格并不适用于我们的需求:
- GFM 语法仅支持 HTML 中部分可用的特性,如果你需要使用 GFM 不支持的表格特性,请使用 HTML。
- 如果 GFM 表格超过了 150 个字符宽度,请使用 HTML。
- 我们支持一种称为“属性表”的特殊表格,它有自己的 CSS 类,因此它只能是 HTML。
所以,一般原则是:你应该在能使用 GFM Markdown 语法时使用它,而在 HTML 的可读性更强时才回退到原生 HTML。参见何时使用 HTML 表格,以获取更多信息。
GFM 表格语法风格
在 GFM 表格的语法中,作者可以省略每一行开头和末尾的管道符。但是,为了可读性,MDN 作者必须保留管道符。此外,作者必须在行内提供尾随空格,以便列中的所有单元格在纯文本中都具有相同的宽度。
也就是说,MDN 作者必须使用以下风格:
| 表头 1 | 表头 2 | 表头 3 |
| -------- | -------- | -------- |
| 单元格 1 | 单元格 2 | 单元格 3 |
| 单元格 4 | 单元格 5 | 单元格 6 |
而不是这种风格:
| 表头 1 | 表头 2 | 表头 3 |
| --------- | --- |----------------------|
| 单元格 1 | 单元格 2 | 单元格 3 |
单元格 4 | 单元格 5 | 单元格 6
幸运的是,表格格式可以由 Prettier 自动修复,因此作者可以依靠 Prettier 来正确地格式化他们的表格。
何时使用 HTML 表格
在以下三种主要情况下应该使用 HTML 表格而不是 GFM 语法:
- 表格使用了 GFM 不支持的特性(见下文)。
- GFM 表格太宽而难以阅读。
- 使用了“属性表”这一特殊类型的表格。
GFM 不支持的表格特性
GFM 表格语法的主要限制是:
- GFM 表格必须有一个标题行。
- GFM 表格可能没有标题列。
- GFM 不会解析单元格中的 GFM 块元素。例如,你不能在单元格中使用列表。
- GFM 表格不能分配类名。
- GFM 不支持除
<table>、<tr>、<th>、<td>以外的任何表格元素。 - GFM 不支持诸如
colspan、rowspan、scope等表格元素属性。
如果你需要使用任何不受支持的特性,那么应该使用 HTML 编写表格。
请注意,我们不建议在表格中经常使用 <caption> 元素,因为这也会无法使用 GFM 语法。
GFM 表格最大宽度
有时,即使可以使用 GFM 编写表格,也应该使用 HTML。因为 GFM 使用“ASCII art”来实现表格,当表格的一行变得过长时,将变得难以阅读。例如,考虑以下表格:
<table>
<tr>
<th>标题 1</th>
<th>标题 2</th>
<th>标题 3</th>
<th>标题 4</th>
<th>标题 5</th>
<th>标题 6</th>
</tr>
<tr>
<td>较短的内容</td>
<td>
涉及了很多细节的更长的内容,以至于表格格式在 GFM 格式中开始变得糟糕起来。
</td>
<td>较短的内容</td>
<td>
另一个包含大量文本的单元格,也涉及到了很多有关特定内容的细节,以至于表格格式在
GFM 格式中开始变得糟糕起来。
</td>
<td>较短的内容</td>
<td>较短的内容</td>
</tr>
</table>
在 GFM 中,它会是这样:
| 标题 1 | 标题 2 | 标题 3 | 标题 4 | 标题 5 | 标题 6 |
| ---------- | ------------------------------------------------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------- | ---------- | ---------- |
| 较短的内容 | 涉及了很多细节的更长的内容,以至于表格格式在 GFM 格式中开始变得糟糕起来。 | 较短的内容 | 另一个包含大量文本的单元格,也涉及到了很多有关特定内容的细节,以至于表格格式在 GFM 格式中开始变得糟糕起来。 | 较短的内容 | 较短的内容 |
在这种情况下,最好使用 HTML。
所以我们遵循以下原则:如果表格的 Markdown 表示将超过 150 个字符宽度,请使用 HTML 编写。
属性表
属性表是一种特殊类型的表格,用于在特定类型的页面集中展示结构化的属性-值内容。这类表格包含两列:第一列为标题列,列出各项属性;第二列则显示该特定项对应的属性值。例如,以下是一个 PannerNode 接口的属性表:
| 输入数量 | 1 |
|---|---|
| 输出数量 | 0 |
| 通道计数模式 | "explicit" |
| 通道数 | 2 |
| 通道解释 | "speakers" |
因为它们有一个标题列,GFM 无法表示这些页面。因此,应该使用 HTML。为了获得特殊的样式,还需要将 "properties" 类应用于表格:
<table class="properties"></table>
讨论参考
此议题已被解决:https://github.com/mdn/content/issues/4325、https://github.com/mdn/content/issues/7342 以及 https://github.com/mdn/content/issues/7898#issuecomment-913265900。
上标和下标
如果有必要,你可以使用 HTML <sup> 和 <sub> 元素,但应尽可能使用替代品。特别是:
- 对于求幂,请使用脱字符:
2^53。 - 对于像 1st 这样的表达式,推荐使用单词,如:“第一”。
- 对于脚注,请不要在脚注的参考文献上使用类似
<sup>[1]</sup>的标注,这是没有必要的。
讨论参考
网页摘要
网页摘要是页面中的第一个“内容”段落——出现在页面元数据(front matter)以及任何侧边栏和网页横幅宏之后的第一段文本内容。
此摘要用于搜索引擎优化(SEO),也被一些宏自动包含在网页列表旁。因此,第一段应即简洁又翔实。
讨论参考
宏
作者在文章中使用宏来模板化常见的链接模式,或包含特定的代码块或文本:
[CSS](/zh-CN/docs/Web/CSS) **`margin`** 属性设置元素的四个边上的外边距区域。它是
{{cssxref("margin-top")}}、{{cssxref("margin-right")}}、{{cssxref("margin-bottom")}}
和 {{cssxref("margin-left")}} 属性的简写形式。
…
参见使用宏以获取更多关于宏的信息。