CommonMark:Markdown 的正式規範

已發表: 2022-03-10
快速總結↬ Markdown 是一種強大的標記語言,它允許以純文本格式進行編輯和格式化,然後可以將其解析並呈現為 HTML。 它具有聲明性語法,對於技術人員和非技術人員來說,它既強大又易於學習。 然而,由於其原始規範中的相應歧義,已經有許多不同的風格(或自定義版本)旨在消除這些歧義並擴展原始語法支持。 這導致了可以解析的內容和渲染的內容之間的巨大差異。 CommonMark 旨在提供反映其實際使用情況的標準化 Markdown 規範。

CommonMark 是 Markdown 語法的合理化版本,其目標是消除原始 Markdown 規範周圍的歧義和不一致。 它提供了一個標準化的規範,定義了語言的通用語法以及一套綜合測試來驗證 Markdown 實現是否符合該規範。

GitHub 使用 Markdown 作為其用戶內容的標記語言。

“CommonMark 是一個雄心勃勃的項目,旨在正式指定 Internet 上許多網站使用的 Markdown 語法,以反映其實際使用情況 [...] 它允許人們在為開發人員提供的同時繼續以他們一貫的方式使用 Markdown一個全面的規範和參考實現,以在平台之間以一致的方式互操作和顯示 Markdown。”

——“GitHub Flavored Markdown 的正式規範”,GitHub 博客

2012 年,GitHub 開始創建自己的 Markdown 風格——GitHub Flavored Markdown (GFM)——以應對 Markdown 標準化的缺乏,並將語法擴展到其需求。 GFM 建立在 Sundown 之上,Sundown 是 GitHub 專門為解決當時現有 Markdown 解析器的一些缺點而構建的解析器。 五年後的 2017 年,它宣布棄用 Sundown,轉而支持 CommonMark 解析和渲染庫,即 GitHub Flavored Markdown 的正式規範中的 cmark。

在 Markdown 和 Visual Studio Code 的常見問題部分中,記錄了 VSCode 中的 Markdown 使用 markdown-it 庫以 CommonMark Markdown 規範為目標,該庫本身遵循 CommonMark 規範。

CommonMark 已被廣泛採用和實現(參見 CommonMark 實現列表),用於不同的語言,如 C(例如 cmark)、C#(例如 CommonMark.NET)、JavaScript(例如 markdown-it)等。這對開發人員來說是個好消息並且作者正在逐漸轉向能夠以一致的語法和標準化的規範使用 Markdown 的新領域。

關於 Markdown 解析器的簡短說明

Markdown 解析器是直接或間接將 Markdown 文本轉換為 HTML 的核心。

像 cmark 和 commonmark.js 這樣的解析器不會直接將 Markdown 轉換為 HTML,而是將其轉換為抽象語法樹 (AST),然後將 AST 呈現為 HTML,從而使處理過程更加精細且易於操作。 例如,在解析 - 到 AST - 和呈現 - 到 HTML 之間,可以擴展 Markdown 文本。

跳躍後更多! 繼續往下看↓

CommonMark 的 Markdown 語法支持

已經將 CommonMark 規範作為其特定風格的基線的項目或平台通常是 CommonMark Markdown 規範嚴格子集集。 在大多數情況下,CommonMark 通過構建一個可構建的規範來減輕很多歧義。 GFM 就是一個典型的例子,雖然它支持所有 CommonMark 語法,但它還對其進行了擴展以適合其使用。

CommonMark 的語法支持一開始可能會受到限制,例如,它不支持此表語法,但重要的是要知道這是設計使然,因為此對話線程中的評論顯示:支持的語法嚴格的,並且說成為語言本身的核心語法——與它的創建者 John Gruber 在 Markdown: Syntax 中指定的相同。

在撰寫本文時,以下是一些受支持的語法:

  1. 段落和換行符,
  2. 標頭,
  3. 強調和強烈的強調,
  4. 水平規則,
  5. 列表,
  6. 鏈接,
  7. 圖片,
  8. 塊引用,
  9. 代碼,
  10. 代碼塊。

為了跟隨示例,建議您使用 commonmark.js dingus 編輯器來嘗試語法並獲取呈現的預覽、生成的 HTML 和 AST。

段落和換行符

在 Markdown 中,段落是由至少一個空行分隔的連續文本行。

以下規則定義了一個段落:

  1. Markdown 段落在 HTML 中呈現為段落元素 <p>。
  2. 不同的段落之間用一個或多個空行分隔。
  3. 對於換行符,段落應該用兩個空格(或其等效的製表符)或反斜杠( \ )作為後綴。
句法呈現的 HTML
這是一行文字<p>這是一行文字</p>
這是一行文字
還有另一行文字
還有一個,但
同款
<p>這是一行文字
還有另一行文字
還有一個,但
同一段</p>
這是一段

還有一段

還有一個
<p>這是一段</p>
<p>還有一段</p>
<p>還有一個</p>
一行文本後的兩個空格
或後置反斜杠\
兩者都意味著換行
<p>一行文本後兩個空格<br /><br>或後置反斜杠<br /><br>都表示換行</p>
  • 交互式教程來了解段落。
  • Dingus 永久鏈接使用預覽和 AST 查看完整示例。
  • 了解有關段落的更多信息。

標題

Markdown 中的 Headings 代表 HTML Heading 元素之一。 定義標題的方法有兩種:

  1. ATX 航向。
  2. 塞文標題。

以下規則定義 ATX 標題:

  1. 支持標題級別 1 ( h1 ) 到標題級別 6 ( h6 )。
  2. Atx 樣式的標題以井號 ( # ) 符號為前綴。
  3. 至少需要有一個空格分隔文本和井號 ( # ) 符號。
  4. 哈希的計數等於標題的基數。 一個哈希是h1 ,兩個哈希是h2 ,6 個哈希是h6
  5. 也可以在標題上附加任意數量的哈希符號,儘管這不會產生任何影響(即# Heading 1 #
句法呈現的 HTML
# 標題 1 <h1>標題 1</h1>
## 標題 2 <h2>標題 2</h2>
### 標題 3 <h3>標題 3</h3>
#### 標題 4 <h4>標題 4</h4>
##### 標題 5 <h5>標題 5</h5>
###### 標題 6 <h6>標題 6</h6>
## 標題 2 ## <h2>標題 2</h2>

以下規則定義了 Settext 標題:

  1. 僅支持標題級別 1 (h1) 和標題級別 2 (h2)。
  2. Settext 樣式定義分別用等號 (=) 和破折號完成。
  3. 對於 Setext,至少需要一個等號或破折號。
句法呈現的 HTML
標題 1
=
<h1>標題 1</h1>
標題 2
-
<h2>標題 2</h2>
  • 交互式教程來了解標題。
  • Dingus 永久鏈接可查看完整示例與預覽和 AST。
  • 了解有關 ATX 航向的更多信息。
  • 了解有關 Settext 標題的更多信息。

強調和強烈的強調

Markdown 中的強調可以是斜體或粗體(強調強調)。

以下規則定義了強調:

  1. 普通強調和強烈強調在 HTML 中分別呈現為 Emphasis、<em> 和 Strong、<strong> 元素。
  2. 由單個星號 ( * ) 或下劃線 ( _ ) 界定的文本將是重點。
  3. 以雙星號或下劃線為界的文本將是一個重點。
  4. 邊界符號(星號或下劃線)必須匹配。
  5. 符號和所附文本之間不得有空格。
句法呈現的 HTML
_Italic_ <em>斜體</em>
*Italic* <em>斜體</em>
__Bold__ <strong>粗體</strong>
**Bold** <strong>粗體</strong>
  • 交互式教程,了解重點。
  • Dingus 永久鏈接可查看完整示例與預覽和 AST。
  • 了解更多關於強調和強調的信息。

水平尺

水平規則 <hr/> 由三個或更多星號 ( * )、連字符 ( - ) 或下劃線 ( _ ) 在新行上創建。 符號由任意數量的空格分隔,或者根本不分隔。

句法呈現的 HTML
*** <hr />
* * * <hr />
--- <hr />
- - - <hr />
___ <hr />
_ _ _ <hr />
  • Dingus 永久鏈接可查看完整示例與預覽和 AST。
  • 了解有關主題休息的更多信息。

列表

Markdown 中的列表要么是項目符號(無序列)列表,要么是有序列表。

以下規則定義了一個列表:

  1. 項目符號列表在 HTML 中呈現為無序列表元素 <ul>。
  2. 有序列表在 HTML 中呈現為有序列表元素 <ol>。
  3. 項目符號列表使用星號、加號和連字符作為標記。
  4. 有序列表使用數字後跟句點或右括號。
  5. 標記必須是一致的(您必須只使用開頭的標記用於列表項定義的其餘部分)。
句法呈現的 HTML
* 一
* 二
* 三
<ul>
<li>一個</li>
<li>兩個</li>
<li>三個</li>
</ul>
+ 一
+ 兩個
+ 三個
<ul>
<li>一個</li>
<li>兩個</li>
<li>三個</li>
</ul>
- 一
- 二
- 三
<ul>
<li>一個</li>
<li>兩個</li>
<li>三個</li>
</ul>
- 一
- 二
+ 三個
<ul>
<li>一個</li>
<li>兩個</li>
</ul>
<ul>
<li>三個</li>
</ul>
1. 一
2. 兩個
3. 三
<ol>
<li>一個</li>
<li>兩個</li>
<li>三個</li>
</ol>
3. 三
4.四個
5. 五
<ol 開始=“3”>
<li>三個</li>
<li>四個</li>
<li>五個</li>
</ol>
1. 一
2. 兩個
3. 三
<ol>
<li>一個</li>
<li>兩個</li>
<li>三個</li>
</ol>
  • 了解列表的交互式教程。
  • Dingus 永久鏈接可查看完整示例與預覽和 AST。
  • 了解有關列表項的更多信息。

鏈接

內聯參考格式支持鏈接。

以下規則定義了一個鏈接:

  1. 鏈接呈現為 HTML Anchor 元素 <a>。
  2. 內聯格式的語法為: [value](URL "optional-title") ,括號之間沒有空格。
  3. 引用格式的語法: [value][id]表示引用, [id]: href "optional-title"表示超鏈接標籤,至少用一行分隔。
  4. id定義標識符,可以由字母、數字、空格和標點符號組成。
  5. 定義標識符不區分大小寫。
  6. 還支持自動鏈接,其中 URL 以小於 (<) 和大於 (>) 符號為界,並按字面顯示。
 <!--Markdown--> [Google](https://google.com “Google”) <!--Rendered HTML--> <a href="https://google.com" title="Google">Google</a> <!--Markdown--> [Google](https://google.com) <!--Rendered HTML--> <a href="https://google.com">Google</a> <!--Markdown--> [Comparing Styling Methods in Next.js](/2020/09/comparing-styling-methods-next-js) <!--Rendered HTML--> <a href="/2020/09/comparing-styling-methods-next-js">Comparing Styling Methods In Next.js</a> <!--Markdown--> [Google][id] <!--At least a line must be in-between--> <!--Rendered HTML--> <a href="https://google.com" title="Google">Google</a> <!--Markdown--> <https://google.com> <!--Rendered HTML--> <a href="https://google.com">google.com</a> <!--Markdown--> <[email protected]> <!--Rendered HTML--> <a href="mailto:[email protected]">[email protected]</a>
  • 交互式教程以了解鏈接。
  • Dingus 永久鏈接可查看完整示例與預覽和 AST。
  • 了解有關鏈接的更多信息。

圖片

Markdown 中的圖像遵循鏈接的內聯參考格式。

以下規則定義圖像:

  1. 圖像被呈現為 HTML 圖像元素 <img>。
  2. 內聯格式的語法為: ![alt text](image-url "optional-title")
  3. 參考格式的語法為: ![alt text][id]用於參考, [id]: image-url "optional-title"用於圖像標籤。 兩者應至少用一個空行分隔。
  4. 圖片標題是可選的,image-url 可以是相對的。
 <!--Markdown--> ![alt text](image-url "optional-title") <!--Rendered HTML--> <img src="image-url" alt="alt text" title="optional-title" /> <!--Markdown--> ![alt text][id] <!--At least a line must be in-between--> <!--Markdown--> <!--Rendered HTML--> <img src="image-url" alt="alt text" title="optional-title" />
  • 交互式教程來了解圖像。
  • Dingus 永久鏈接可查看完整示例與預覽和 AST。
  • 了解有關圖像的更多信息。

塊引用

HTML 塊引用元素 <blockquote> 可以通過在新行前加上大於號 ( > ) 來創建。

 <!--Markdown--> > This is a blockquote element > You can start every new line > with the greater than symbol. > That gives you greater control > over what will be rendered. <!--Rendered HTML--> <blockquote> <p>This is a blockquote element You can start every new line with the greater than symbol. That gives you greater control over what will be rendered.</p> </blockquote>

塊引用可以嵌套:

 <!--Markdown--> > Blockquote with a paragraph >> And another paragraph >>> And another <!--Rendered HTML--> <blockquote> <p>Blockquote with a paragraph</p> <blockquote> <p>And another paragraph</p> <blockquote> <p>And another</p> </blockquote> </blockquote> </blockquote>

它們還可以包含其他 Markdown 元素,如標題、代碼、列表項等。

 <!--Markdown--> > Blockquote with a paragraph > # Heading 1 > Heading 2 > - > 1. One > 2. Two <!--Rendered HTML--> <blockquote> <p>Blockquote with a paragraph</p> <h1>Heading 1</h1> <h2>Heading 2</h2> <ol> <li>One</li> <li>Two</li> </ol> </blockquote>
  • 交互式教程,了解塊引用。
  • Dingus 永久鏈接可查看完整示例與預覽和 AST。
  • 了解有關 Blockquotes 的更多信息。

代碼

還支持 HTML 內聯代碼元素 <code>。 要創建一個,請使用反引號 (`) 分隔文本,如果需要在封閉文本中使用文字反引號,則使用雙反引號。

 <!--Markdown--> `inline code snippet` <!--Rendered HTML--> <code>inline code snippet</code> <!--Markdown--> `<button type='button'>Click Me</button>` <!--Rendered HTML--> <code><button type='button'>Click Me</button></code> <!--Markdown--> `` There's an inline back-tick (`). `` <!--Rendered HTML--> <code>There's an inline back-tick (`).</code>
  • 交互式教程來了解代碼。
  • Dingus 永久鏈接可查看完整示例與預覽和 AST。
  • 了解有關代碼跨度的更多信息。

代碼塊

還支持 HTML 預格式化文本元素 <pre>。 這可以通過至少三個和相等數量的邊界反引號 ( ` ) 或波浪線 ( ~ ) 來完成 - 通常稱為代碼圍欄,或至少 4 個空格的新行開始縮進。

 <!--Markdown--> ``` const dedupe = (array) => [...new Set(array)]; ``` <!--Rendered HTML--> <pre><code>const dedupe = (array) => [...new Set(array)];</code></pre> <!--Markdown--> const dedupe = (array) => [...new Set(array)]; <!--Rendered HTML--> <pre><code>const dedupe = (array) => [...new Set(array)];</code></pre>
  • 交互式教程來了解代碼。
  • Dingus 永久鏈接可查看完整示例與預覽和 AST。
  • 了解有關 Fenced 和 Indented 代碼塊的更多信息。

使用內聯 HTML

根據 John Grubers 關於內聯 HTML 的原始規範說明,任何 Markdown 語法未涵蓋的標記,您只需使用 HTML 本身,唯一的限制是塊級 HTML 元素 - 例如<div><table><pre><p>等 — 必須用空行與周圍的內容分隔,並且塊的開始和結束標記不應使用製表符或空格縮進。

但是,除非您可能是 CommonMark 本身或附近的人之一,否則您很可能會使用已經擴展以處理 CommonMark當前不支持的大量語法的風格編寫 Markdown。

向前走

CommonMark 是一項持續不斷的工作,其規範最後更新於 2019 年 4 月 6 日。Markdown 工具池中有許多流行的應用程序支持它。 有了 CommonMark 對標準化的努力的認識,我認為足以得出結論,在 Markdown 的簡單性中,有很多工作在幕後進行,對於 CommonMark 的努力來說,GitHub Flavored Markdown 的正式規範是一件好事是基於規範。

向 CommonMark 標準化工作的轉變並不會阻止創建風格以擴展其支持的語法,並且隨著 CommonMark 為 1.0 版準備好必須解決的問題,有一些關於持續努力的有趣資源可以用於您的細讀。

資源

  • John Gruber 介紹 Markdown
  • CommonMark 官方網站
  • GitHub 風格的 Markdown 規範
  • cmark 官方回購
  • GitHub 的 cmark 分支
  • 維基百科上的降價
  • 降價指南