如何在 Markdown 中编写

此页面描述了我们如何使用 Markdown 在 MDN Web Docs 上编写文档。我们选择了 GitHub Flavored Markdown (GFM) 作为基线,并添加了一些扩展来支持我们在 MDN 上需要做的一些事情,而这些事情在 GFM 中并不容易得到支持。

基线:GitHub Flavored Markdown

MDN Markdown 的基线是 GitHub Flavored Markdown (GFM):https://github.github.com/gfm/。这意味着您可以参考 GFM 规范中未在此页面中明确指定的任何内容。GFM 本身是 CommonMark 的超集(https://spec.commonmark.org/)。

GFM 规范定义了两种基本类型的链接

  • 内联链接,其中目标紧跟在链接文本之后。
  • 引用链接,其中目标在文档的其他位置定义。

在 MDN 上,我们只允许内联链接。

这是在 MDN 上编写 GFM 链接的正确方法

md
[Macarons](https://en.wikipedia.org/wiki/Macaron) are delicious but tricky to make.

这是在 MDN 上编写链接的错误方法

md
[Macarons][macaron] are delicious but tricky to make.

[macaron]: https://en.wikipedia.org/wiki/Macaron

示例代码块

在 GFM 和 CommonMark 中,作者可以使用“代码围栏”来界定<pre>块。代码围栏的开头后面可能会跟着一些文本,称为“信息字符串”。规范说明如下

信息字符串的第一个单词通常用于指定代码示例的语言,并在代码标签的 class 属性中呈现。

信息字符串可以包含多个单词,例如

md
```fee fi fo fum
// some example code
```

在 MDN 上,作者将使用代码围栏作为示例代码块。他们必须使用信息字符串的第一个单词指定代码示例的语言,这将用于为代码块提供语法高亮。支持以下单词

  • 编程语言
    • JavaScript
      • js - JavaScript
      • ts - TypeScript
      • jsx - React JSX
      • tsx - React TSX
    • C 类
      • c - C
      • cpp - C++
      • cs - C#
      • java - Java
    • 其他
      • python - Python
      • php - PHP
      • rust - Rust
      • glsl - GLSL (OpenGL 着色器)
      • sql - SeQueL 命令
      • wasm - WebAssembly
      • webidl - Web 接口定义语言
  • 样式
    • css - CSS
    • scss - Sass (SCSS)
    • less - Less
  • 标记
    • html - HTML
    • svg - SVG
    • xml - XML
    • mathml - MathML
    • md - Markdown
    • latex - LaTeX
  • 命令提示符
    • bash - Bash/Shell
    • batch - 批处理 (Windows Shell)
    • powershell - PowerShell
  • 配置文件/数据文件
    • json - JSON
    • ini - INI
    • yaml - YAML
    • toml - TOML
    • sql - SQL 数据库
    • ignore - Gitignore 文件
    • apacheconf - Apache 配置
    • nginx - NGINX 配置
  • 模板
    • django - Django 模板
    • svelte - Svelte 模板
    • handlebars - Handlebars 模板
    • pug - Pug 模板(可能由Express使用)
  • 其他
    • plain - 纯文本
    • diff - Diff 文件
    • http - HTTP 标头
    • regex - 正则表达式
    • uri - URI 和 URL

例如

md
```js
const greeting = "I will get JavaScript syntax highlighting";
```

如果您希望使用的突出显示未在上面列出,则应将代码块标记为plain。可以在GitHub 上讨论的过程中请求其他语言。

抑制代码检查

作者可以向任何语言标识符添加-nolint后缀

md
```html-nolint
<p>
I will not be linted.
</p>
```

这样的代码块将获得适当的语法高亮,并将被实时示例系统识别,但会被代码检查工具或像 Prettier 这样的自动格式化程序忽略。作者应使用此后缀来显示无效代码或代码检查工具或格式化程序不应修复的备用格式。

其他类(信息字符串)

GFM 支持信息字符串,允许作者提供有关代码块的其他信息。在 MDN 上,信息字符串将转换为类名。

作者将能够提供以下任何一个信息字符串

  • example-good:将此示例样式化为良好示例(应遵循的示例)
  • example-bad:将此示例样式化为不良示例(应避免的示例)
  • hidden:不要在页面中呈现此代码块。这用于实时示例中。

例如

md
```js example-good
const greeting = "I'm a good example";
```

```js example-bad
const greeting = "I'm a bad example";
```

```js hidden
const greeting = "I'm a secret greeting";
```

这些将呈现为

js
const greeting = "I'm a good example";
js
const greeting = "I'm a bad example";

讨论参考

注释、警告和提示

作者可以使用GFM 警告语法来特别关注内容。有三种类型的警告:注释、警告和提示。

注意:MDN Web Docs 在支持 GFM 警告之前使用其自己的语法支持警告,并将其称为“noteblocks”。MDN 不支持以下 GFM 警告:[!TIP][!CAUTION][!IMPORTANT]。GFM 不支持[!CALLOUT]

  • 要添加注释,请创建一个其第一行为[!NOTE]的块引用。
  • 要添加警告,请创建一个其第一行为[!WARNING]的块引用。
  • 要添加提示,请创建一个其第一行为[!CALLOUT]的块引用。

注释和警告将在输出的开头添加本地化的注意:警告:,而提示则不会。这使得提示成为作者想要提供自定义标题时的不错选择。

警告:在旧的 MDN 语法中,类型是本地化的并以粗体文本添加到第一段中,即**注意:**Foo bar而不是[!NOTE] ⏎ Foo bar

为了迁移目的,仍然支持旧语法。在新的文档中避免使用它。

警告:目前,由于Prettier 错误,如果注释或警告的第一个字符是格式化符号(例如反引号、星号、方括号或花括号),则无法使用 GFM 警告语法。在这种情况下,请改用旧语法> **注意:**。作者不需要改写内容来解决格式化程序的问题。

多行通过与普通段落相同的空块引用行生成。此外,没有空格的多行也像普通的 Markdown 行一样处理,并连接在一起。

块引用可以包含代码块或其他块元素。

示例

注释

md
> [!NOTE]
> This is how you write a note.
>
> It can have multiple lines.

这将生成以下 HTML

html
<div class="notecard note">
  <p><strong>Note:</strong> This is how you write a note.</p>
  <p>It can have multiple lines.</p>
</div>

此 HTML 将呈现为突出显示的框

注意:这是编写注释的方法。

它可以有多行。

警告

md
> [!WARNING]
> This is how you write a warning.
>
> It can have multiple paragraphs.

这将生成以下 HTML

html
<div class="notecard warning">
  <p><strong>Warning:</strong> This is how you write a warning.</p>
  <p>It can have multiple paragraphs.</p>
</div>

此 HTML 将呈现为突出显示的框

警告:这是编写警告的方法。

它可以有多个段落。

提示

md
> [!CALLOUT]
>
> **This is how you write a callout.**
>
> It can have multiple paragraphs.

这将生成以下 HTML

html
<div class="callout">
  <p><strong>This is how you write a callout.</strong></p>
  <p>It can have multiple paragraphs.</p>
</div>

此 HTML 将呈现为突出显示的框

这是编写提示的方法。

它可以有多个段落。

包含代码块的注释

此示例包含代码块。

md
> [!NOTE]
> This is how you write a note.
>
> It can contain code blocks.
>
> ```js
> const s = "I'm in a code block";
> ```
>
> Like that.

这将生成以下 HTML

html
<div class="notecard note">
  <p><strong>Note:</strong> This is how you write a note.</p>
  <p>It can contain code blocks.</p>
  <pre class="brush: js">const s = "I'm in a code block";</pre>
  <p>Like that.</p>
</div>

此 HTML 将与代码块一起呈现

注意:这是编写注释的方法。

它可以包含代码块。

js
const s = "I'm in a code block";

就像那样。

讨论参考

定义列表

定义列表在 MDN 中很常见,但 GFM 不支持。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> 中。
  • 最终嵌套 <ul> 中的 <li> 元素将被解析为一个 GFM <li> 元素,其内部内容将构成 <dd> 的内容,但开头的 ": " 将被丢弃。

例如,这是一个 <dl>

md
- term1

  - : My description of term1

- `term2`

  - : My description of term2

    It can have multiple paragraphs, and code blocks too:

    ```js
    const thing = 1;
    ```

在 GFM/CommonMark 中,这将生成以下 HTML

html
<ul>
  <li>
    <p>term1</p>
    <ul>
      <li>: My description of term1</li>
    </ul>
  </li>
  <li>
    <p><code>term2</code></p>
    <ul>
      <li>
        <p>: My description of term2</p>
        <p>It can have multiple paragraphs, and code blocks too:</p>
        <pre>
          <code class="brush: js">const thing = 1;</code>
        </pre>
      </li>
    </ul>
  </li>
</ul>

在 MDN 上,这将生成以下 HTML

html
<dl>
  <dt>
    <p>term1</p>
  </dt>
  <dd>My description of term1</dd>
  <dt>
    <p><code>term2</code></p>
  </dt>
  <dd>
    <p>My description of term2</p>
    <p>It can have multiple paragraphs, and code blocks too:</p>
    <pre>
       <code class="brush: js">const thing = 1;</code>
    </pre>
  </dd>
</dl>

使用此语法编写的定义列表必须由成对的 <dt>/<dd> 元素组成。使用此语法,无法编写一个列表,其中包含多个连续的 <dt> 元素或多个连续的 <dd> 元素:解析器会将此视为错误。我们预计 MDN 上几乎所有定义列表都能在此限制下工作,而对于那些不能工作的列表,作者可以回退到原始 HTML。

这是不允许的

md
- `param1`, `param2`, `param3`
  - : My description of `param1`
  - : My description of `param2`
  - : My description of `param3`

作为一种解决方法,对于作者需要将多个 <dt> 项目与单个 <dd> 关联的情况,请考虑将它们作为单个 <dt> 提供,该 <dt> 包含多个用逗号分隔的术语,如下所示

md
- `param1`, `param2`, `param3`
  - : My description of params 1, 2, and 3

此处描述的语法的基本原理是,它与期望 CommonMark 的工具(例如 Prettier 或 GitHub 预览)配合使用效果很好,同时编写和解析起来也相对容易。

讨论参考

此问题已在 https://github.com/mdn/content/issues/4367 中解决。

表格

GFM 提供了一种用于创建 表格 的语法,我们在 MDN 中使用了这种语法。但是,有时 GFM 表格不适合我们的需求

  • GFM 语法仅支持 HTML 中可用功能的一个子集。如果需要使用 GFM 中不支持的表格功能,请使用 HTML 创建表格。
  • 如果表格的 GFM 表示超过 150 个字符宽,请使用 HTML 创建表格。
  • 我们支持一种称为“属性表”的特殊表格,它有自己的 CSS 类,因此始终为 HTML。

因此,一般原则是在作者可以的情况下使用 GFM Markdown 语法,并在必须使用或 HTML 更易读时回退到原始 HTML。有关更多信息,请参阅 何时使用 HTML 表格

GFM 表格语法样式

在 GFM 表格语法中,作者可以省略行的开头和结尾管道。但是,为了提高可读性,MDN 作者必须包含这些管道。此外,作者必须在行中提供尾随空格,以便同一列中的所有单元格在纯文本中具有相同的长度。

也就是说,MDN 作者必须使用此样式

md
| Heading 1 | Heading 2 | Heading 3 |
| --------- | --------- | --------- |
| cell 1    | cell 2    | cell 3    |
| cell 4    | cell 5    | cell 6    |

而不是此样式

md
| Heading 1 | Heading 2 | Heading 3 |
| --------- | --- |----------------------|
| cell 1 | cell 2 | cell 3 |
cell 4 | cell 5 | cell 6

幸运的是,表格格式由 Prettier 自动修复,因此作者可以依靠 Prettier 正确格式化他们的表格。

何时使用 HTML 表格

作者应该使用 HTML 表格而不是 GFM 语法主要有三种情况

  1. 表格使用 GFM 不支持的功能(见下文)。
  2. GFM 表格太宽,无法阅读。
  3. 作者想要一种称为“属性表”的特殊类型的表格。

GFM 中不支持的表格功能

GFM 表格语法的主要限制是

  • GFM 表格必须具有标题行。
  • GFM 表格可能没有标题列。
  • GFM 不会解析表格单元格中的 GFM 块级元素。例如,您不能在表格单元格中包含列表。
  • GFM 表格不能分配类。
  • GFM 不支持除 <table><tr><th><td> 之外的任何表格元素。
  • GFM 不支持任何表格元素属性,例如 colspanrowspanscope

如果作者需要使用任何不受支持的功能,则应使用 HTML 编写表格。

请注意,我们不建议普遍使用表格上的 <caption> 元素,因为这也会排除 GFM 语法。

GFM 表格最大宽度

即使表格可以用 GFM 编写,有时也最好使用 HTML,因为 GFM 使用了一种"ASCII 艺术"方法来创建表格,当表格行变长时,这种方法的可读性很差。请考虑以下表格

html
<table>
  <tr>
    <th>A heading 1</th>
    <th>A heading 2</th>
    <th>A heading 3</th>
    <th>A heading 4</th>
    <th>A heading 5</th>
    <th>A heading 6</th>
  </tr>
  <tr>
    <td>Something shortish</td>
    <td>
      Something much longer that really goes into a lot of detail about
      something, so much so that the table formatting starts to look bad in GFM
      format.
    </td>
    <td>Something shortish</td>
    <td>
      Another cell with lots of text in it, that also really goes into a lot of
      detail about something, so much so that the table formatting starts to
      look bad in GFM format.
    </td>
    <td>Something shortish</td>
    <td>Something shortish</td>
  </tr>
</table>

在 GFM 中,这将显示为

md
| A heading 1        | A heading 2                                                                                                                                         | A heading 3        | A heading 4                                                                                                                                                              | A heading 5        | A heading 6        |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------ | ------------------ |
| Something shortish | Something much longer that really goes into a lot of detail about something, so much so that the table formatting starts to look bad in GFM format. | Something shortish | Another cell with lots of text in it, that also really goes into a lot of detail about something, so much so that the table formatting starts to look bad in GFM format. | Something shortish | Something shortish |

在这种情况下,最好使用 HTML。

这导致我们得出以下指南:如果表格的 Markdown 表示超过 150 个字符宽,请使用 HTML 创建表格

属性表

属性表是一种特定类型的表格,用于跨特定类型的一组页面显示结构化的属性-值内容。这些表格有两列:第一列是标题列,列出属性,第二列列出此特定项目的属性值。例如,以下是 PannerNode 接口的属性表

输入数量 1
输出数量 0
通道计数模式 "显式"
通道数 2
通道解释 "扬声器"

这些页面无法在 GFM 中表示,因为它们具有标题列,因此作者在这种情况下应使用 HTML。为了获得特殊的样式,作者应将 "properties" 类应用于表格

html
<table class="properties"></table>

讨论参考

上标和下标

如果需要,编写者可以使用 HTML <sup><sub> 元素,但应尽可能使用替代方案。特别是

  • 对于求幂,使用插入符号:2^53
  • 对于序数表达式(如 1st),首选单词(如“first”)。
  • 对于脚注,不要标记脚注引用,例如 <sup>[1]</sup>

讨论参考

此问题已在 https://github.com/mdn/content/issues/4578 中解决。

页面摘要

页面摘要是页面中的第一个“内容”段落——出现在页面前置信息以及任何 侧边栏页面横幅 宏之后的第一个文本。

此摘要用于搜索引擎优化 (SEO),并且还由某些宏自动包含在页面列表中。因此,第一段应该既简洁又信息丰富。

讨论参考

此问题已在 https://github.com/mdn/content/issues/3923 中解决。

KumaScript

编写者将能够在散文内容中包含 KumaScript 宏调用

md
The **`margin`** [CSS](/en-US/docs/Web/CSS) property
sets the margin area on all four sides of an element. It is a shorthand for
{{cssxref("margin-top")}}, {{cssxref("margin-right")}}, {{cssxref("margin-bottom")}},
and {{cssxref("margin-left")}}.

{{EmbedInteractiveExample("pages/css/margin.html")}}

The top and bottom margins have no effect on replaced inline elements, such as
{{HTMLElement("span")}} or {{HTMLElement("code")}}.

有关宏的更多信息,请参阅 使用宏