如何使用 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 和 CommonMark 中,你可以使用“围栏代码块”来标示 <pre>
块。围栏代码块的起始位置后可以添加“信息字符串”。规范中写道:
信息字符串的第一个单词常用于指定示例代码的语言,并呈现在代码标签的 class 属性中。
信息字符串可包含多个单词,例如:
```fee fi fo fum
// 一些示例代码
```
在 MDN,你可以使用围栏代码块展现示例代码块。且必须使用信息字符串的第一个单词指定示例代码的语言,这将用于提供代码块的语法高亮。MDN 支持以下的语言词:
- 编程语言
- JavaScript
js
——JavaScriptts
——TypeScriptjsx
——React JSXtsx
——React TSX
- 类 C 语言
c
——C 语言cpp
——C++cs
——C#java
——Java
- 其他
python
——Pythonphp
——PHPrust
——Rustglsl
——GLSL(OpenGL 着色器)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 讨论提出的流程请求其他语言的高亮支持。
阻止 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 文档在 GFM 添加 noteblock 语法之前就已经支持了自己的备注块语法。因此,MDN 仅支持 GFM 支持的五种备注块类型中的两种,并且支持另一种 GFM 不支持的类型。
- 要添加备注,请创建一个 GFM 块引用,起始行为
[!NOTE]
。 - 要添加警告,请创建一个 GFM 块引用,起始行为
[!WARNING]
。 - 要添加标注,请创建一个 GFM 块引用,起始行为
[!CALLOUT]
。
备注和警告将在输出中添加本地化的“备注:”或“警告:”,而标注不会。当你想要提供自定义标题时,标注会是一个不错的选择。
警告:
在旧的 MDN 语法中,类型是本地化的,并且会以粗体文本添加到第一个段落中,例如 **备注:** Foo bar
而不是 [!NOTE] ⏎ Foo bar
。出于迁移的目的,此语法仍受支持。但请避免在新文档中使用。
多行块引用由空的块引用生成,就像普通的段落一样。此外,没有空格的多行内容会像常规 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 作者必须使用以下风格:
| Heading 1 | Heading 2 | Heading 3 |
| --------- | --------- | --------- |
| cell 1 | cell 2 | cell 3 |
| cell 4 | cell 5 | cell 6 |
而不是这种风格:
| Heading 1 | Heading 2 | Heading 3 |
| --------- | --- |----------------------|
| cell 1 | cell 2 | cell 3 |
cell 4 | cell 5 | cell 6
幸运的是,表格格式可以由 Prettier 自动修复,因此作者可以依靠 Prettier 来正确地格式化他们的表格。
何时使用 HTML 表格
在以下三种主要情况下应该使用 HTML 表格而不是 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 编写。
属性表
属性表是一类特殊的表格,用于在一组特定类型的页面中显示结构化的属性值。例如,所有的 Event 页面都有一个属性表,列出了关于事件的常见信息:是否冒泡、是否可取消等等。
这类表格有两列:第一列是标题列,其列出了属性名;第二列则列出了这些特定属性的值。例如,以下是一个 PannerNode
接口的属性表:
输入数量 | 1 |
---|---|
输出数量 | 0 |
通道计数模式 | "explicit" |
通道数 | 2 |
通道解释 | "speakers" |
因为它们有一个标题列,GFM 无法表示这些页面。因此,应该使用 HTML。为了获得特殊的样式,还需要将 "properties"
类应用于表格:
<table class="properties"></table>
讨论参考
上标和下标
讨论参考
网页摘要
讨论参考
KumaScript
文本内容可以包括对 KumaScript 宏的调用:
[CSS](/zh-CN/docs/Web/CSS) **`margin`** 属性设置元素的四个边上的外边距区域。它是
{{cssxref("margin-top")}}、{{cssxref("margin-right")}}、{{cssxref("margin-bottom")}}
和 {{cssxref("margin-left")}} 属性的简写形式。
{{EmbedInteractiveExample("pages/css/margin.html")}}
顶部和底部外边距对放置的行级元素(例如,{{HTMLElement("span")}} 或 {{HTMLElement("code")}})没有影响。
参见使用宏以获取更多关于宏的信息。