很多人第一次接觸 Markdown 通常是在 GitHub 上看到 README,或是用 Notion、Obsidian、HackMD 寫筆記的時候。它的設計目的非常單純:用最少的符號讓純文字看起來就像排版過一樣,不需要切換到 WYSIWYG 編輯器,就能寫出有標題、清單、連結與程式碼區塊的文件。這篇文章會從 Markdown 的來歷講起,整理原生 Markdown 與 CommonMark 規範定義的核心語法,再清楚區分 GitHub Flavored Markdown(GFM) 多出來的擴充功能,最後談一下不同平台之間的相容性陷阱。

Markdown 是什麼,從哪裡來

Markdown 是 2004 年由 John GruberAaron Swartz 共同設計的一種輕量標記語言。當時 Gruber 想解決的問題很具體:寫部落格時,HTML 標籤太繁瑣,而所見即所得編輯器又常常產出髒亂的 HTML。他希望有一種寫法可以讓純文字「不渲染也看得懂、渲染後又能變成乾淨的 HTML」。

所以 Markdown 的設計哲學從一開始就是 易讀易寫,符號的選擇大多模仿純文字 email 時代大家本來就會用的習慣,例如用 * 包住一段字當強調、用 - 開頭表示清單。這也是為什麼一份 Markdown 原始檔在 GitHub、Notion、終端機 cat 出來都還算可讀,不像 HTML 那樣需要先渲染才看得懂結構。

不過 Gruber 最初的規範寫得相當寬鬆,邊角案例(例如巢狀清單、強調符號內含空格)每個 parser 各自解讀,於是 2014 年由 GitHub、Stack Exchange 等公司主導推出了 CommonMark,把語法的歧義一條一條釐清成嚴格規範。現在大多數現代 Markdown 解析器(markdown-itremarkpandoccmark)都以 CommonMark 為基礎再做擴充。

Markdown 從純文字經由 Parser 解析成 AST,再輸出為 HTML 的流程圖
圖 1:Markdown 渲染流程

Markdown 本身不是一個顯示格式,它只是一份純文字。真正會被瀏覽器顯示的是經過 parser 解析、再輸出成的 HTML。中間會經過一個叫做 AST(抽象語法樹)的結構化中介資料,這是為什麼同一份 .md 在不同網站上看起來可能略有差異——差別就在每個 parser 對規範的實作細節。

原生 Markdown 與 GFM 的差別

寫 Markdown 之前要先意識到一件事:不是所有平台都吃同一份語法。原生 Markdown / CommonMark 是核心規範,GitHub Flavored Markdown(GFM)則是 GitHub 在這個基礎上多加的一層擴充。

原生 Markdown 與 GitHub Flavored Markdown 的範圍對照圖,GFM 為 CommonMark 的超集
圖 2:原生 Markdown 與 GFM 範圍對照

關係很單純:GFM 是 CommonMark 的超集。寫在 CommonMark 裡的所有東西在 GitHub 上一定能渲染,但反過來不成立——GFM 才有的表格、任務清單、Alerts 在某些只支援 CommonMark 的平台會以原文顯示。下面分兩節分別介紹。

原生 Markdown 語法(CommonMark 核心)

以下這些是 2004 年 Gruber 原始定義、後來被 CommonMark 標準化的語法,幾乎所有 Markdown 渲染器都支援。

標題

# 一級標題(h1)
## 二級標題(h2)
### 三級標題(h3)
#### 四級
##### 五級
###### 六級
▼ 顯示結果
一級標題(h1)
二級標題(h2)
三級標題(h3)
四級
五級
六級

# 後面要接一個半形空格再寫標題文字。一份文件裡通常只用一個 #,剩下用 ##### 分章節,避免 SEO 上多個 h1 帶來的混亂。

強調與行內格式

**粗體** 或 __粗體__
*斜體* 或 _斜體_
***粗斜體***
`行內程式碼`
▼ 顯示結果
粗體粗體
斜體斜體
粗斜體
行內程式碼

*_ 在原生 Markdown 是等價的,差別只在某些 parser 對「字內強調」(例如 foo_bar_baz)的處理:CommonMark 規定底線版本不會在字中間斷開,而星號版本可以,這是寫程式相關文件時常踩的小坑。

清單

- 無序清單第一項
- 第二項
  - 巢狀子項目(前面要縮排兩個空格)
- 第三項

1. 有序清單
2. 第二項
3. 第三項
▼ 顯示結果
  • 無序清單第一項
  • 第二項
    • 巢狀子項目(前面要縮排兩個空格)
  • 第三項
  1. 有序清單
  2. 第二項
  3. 第三項

有趣的是有序清單的數字其實不重要,全部寫 1. 也會自動編號,渲染器只看「第一個項目用哪個數字起頭」決定起點。

連結與圖片

[連結文字](https://example.com)
[帶 title 的連結](https://example.com "滑鼠停留時顯示")

![圖片替代文字](image.png)
![遠端圖片](https://example.com/banner.jpg)
▼ 顯示結果
連結文字
帶 title 的連結(滑鼠移上去會出現提示)
[ 圖片:圖片替代文字 ]

圖片語法跟連結幾乎一樣,差別只在前面多一個 !。圖片的 alt 文字對 SEO 與無障礙閱讀都很重要,不要偷懶留白。

引用、程式碼區塊與分隔線

> 這是引用區塊,常用來標示別人的話或重點
> 可以連續多行

```
這是程式碼區塊
保留原始換行與縮排
```

---

上面是分隔線(可以用 ---、***、___ 任一個)
▼ 顯示結果
這是引用區塊,常用來標示別人的話或重點
可以連續多行
這是程式碼區塊
保留原始換行與縮排

(上方那條是分隔線)

三個反引號(backtick)開頭與結尾的程式碼區塊是 CommonMark 的標準,但「在程式碼區塊後面接語言名稱」這個語法雖然非常普遍,其實是 GFM 帶起來的擴充。原生 CommonMark 規範允許 parser 自訂如何處理那段「info string」,下一節會再提。

內嵌 HTML

Markdown 從第一天就允許直接寫 HTML 標籤。當 Markdown 的語法不夠用、需要更精細控制(例如自訂 class、放 <details> 收合區塊),可以直接把 HTML 寫進去,渲染器會原樣輸出。這是 Markdown 設計上很務實的選擇——不另造一套自己處理不來的功能,需要時就退回 HTML。

GitHub Flavored Markdown 額外功能

GitHub 從 2017 年正式發佈 GFM 規範,內容是「CommonMark + 一組擴充」。下面這些語法在 GitHub、GitLab、許多現代 Markdown 編輯器都能用,但不在 CommonMark 核心規範內

表格

| 欄位 A | 欄位 B | 欄位 C |
| ----- | :---: | ----: |
| 靠左   | 置中   | 靠右   |
| 內容   | 內容   | 內容   |

第二列的 :--- 控制對齊:左邊冒號靠左、兩邊冒號置中、右邊冒號靠右。原生 Markdown 沒有表格語法,要做表格只能直接寫 <table>

任務清單

- [x] 已完成的事項
- [ ] 待辦事項
- [ ] 另一個待辦

在 GitHub Issue 與 PR 描述裡,這個語法甚至會變成可點擊的核取方塊,是 GFM 最常被使用的擴充之一。

刪除線

~~這段文字會被劃掉~~
GitHub 預覽畫面

語法高亮

```python
def hello(name: str) -> None:
    print(f"Hello, {name}")
```
GitHub 預覽畫面

CommonMark 也允許程式碼區塊後面寫語言名稱,但「依不同語言對關鍵字上色」這件事是 GitHub 把它落地成預設行為,後續才被各大平台跟進。

自動連結

在 GFM 裡,直接貼上一個網址(例如 https://klab.tw)就會自動變成可點擊的連結,不需要包 <>[]() 語法。原生 CommonMark 必須用 <https://klab.tw> 才會自動連結。

提及與 issue 連結

@kyle 幫我看一下這個 PR
這個問題在 #123 已經討論過
跨倉庫引用 owner/repo#456

這類「平台感知」的語法只在 GitHub 站內有效,丟到其他渲染器只會以原文顯示。

Alerts 提示框

> [!NOTE]
> 一般說明訊息

> [!TIP]
> 給讀者的小技巧

> [!IMPORTANT]
> 重要提醒

> [!WARNING]
> 警告訊息

> [!CAUTION]
> 危險訊息
GitHub 預覽畫面

Alerts 是 GitHub 在 2023 年推出的擴充,建立在 CommonMark 的引用語法上,加上 [!TYPE] 的標記。在 GitHub 與 GitLab 上會渲染成彩色的提示框,但在大多數一般 Markdown 渲染器上仍然只會顯示成普通的引用區塊。

Mermaid 圖表

```mermaid
graph LR
    A[使用者] --> B[API Gateway]
    B --> C[Service]
    C --> D[(Database)]
```

把語言指定為 mermaid,GitHub 會自動把區塊內容渲染成流程圖、時序圖、甘特圖等。這是用純文字描述圖形的標準做法,現在也被 GitLab、Notion、Obsidian 等廣泛支援。

數學公式

行內公式:$E = mc^2$
區塊公式:

$$
\sum_{i=1}^{n} i = \frac{n(n+1)}{2}
$$
GitHub 預覽畫面

GitHub 在 2022 年加入內建的 LaTeX 數學支援,採用 KaTeX 渲染。這也是 GFM 的一部分,CommonMark 沒有定義數學公式語法。

相容性陷阱與寫作建議

寫 Markdown 最容易踩的坑就是「在 A 平台寫得好好的,貼到 B 平台就壞了」。整理幾個常見狀況:

狀況原因解法
表格無法渲染目標平台只吃 CommonMark改寫成 <table> 或換用支援 GFM 的平台
單一換行被吃掉CommonMark 預設兩個空格或空行才算斷行用空行分段,或行尾加兩個空格
[!NOTE] Alerts 變成普通引用非 GitHub/GitLab 環境不認得降級寫成 > 注意: 風格
Mermaid 顯示成程式碼該平台沒整合 Mermaid 渲染器改放靜態圖片,或在文末附原始碼連結
巢狀清單錯位縮排空格數不一致每層固定 2 或 4 個空格,全文一致

另一個值得提的細節是原始碼可讀性。Markdown 的初衷就是純文字也要能讀,所以寫的時候盡量讓 .md 本身就排版整齊:標題前後留空行、長段落不要硬塞成一行、表格欄位手動對齊。這些對最終 HTML 渲染結果完全沒影響,但別人 review PR 或在終端機看 README 時會輕鬆很多。

寫 Markdown 的常用工具

實務上不太需要記住每個語法,挑一個合用的編輯器就會自動補完。以下是常見選擇:

  • VS Code:內建即時預覽(Cmd/Ctrl + Shift + V),搭配 Markdown All in One 等套件能自動補表格、產生目錄
  • Obsidian:本地端的筆記工具,全部以 .md 儲存,適合長期累積知識庫
  • Typora:付費的所見即所得 Markdown 編輯器,寫的時候直接看到渲染結果
  • HackMD / HedgeDoc:線上協作 Markdown,支援即時多人編輯
  • pandoc:命令列工具,可以把 Markdown 轉成 HTML、PDF、Word、ePub 等多種格式,是技術寫作圈的瑞士刀

如果只是寫 GitHub README 或 Issue,直接在 GitHub 網頁上的編輯器寫就好,它的預覽分頁會即時顯示渲染結果,也是熟悉 GFM 最快的方式。對於想理解每個語法在 CommonMark 規範下的標準行為,可以到 CommonMark Dingus 即時測試自己的寫法會被怎麼解析。

我自己也另外做了一個免登入、純瀏覽器運作的線上 Markdown 編輯器 ai.klab.tw/markdown ,左邊輸入、右邊即時預覽,支援前面介紹的 GFM 語法(表格、任務清單、語法高亮),也內建 Mermaid 圖表渲染,貼一段 ```mermaid 區塊就能看到流程圖、時序圖直接畫出來。寫完還可以一鍵匯出成 HTML、PNG、PDF,要丟到簡報、信件或印出來都很方便。沒裝 VS Code、不想開 GitHub 草稿時,是個很方便的暫存區。

Markdown 的核心價值不是它有多少語法,而是它在「易寫」與「夠用」之間找到的平衡點。學會原生語法已經能應付 90% 的寫作需求,再往 GFM 加上表格、Alerts、Mermaid,就足以撐起一份完整的技術文件。需要更精細的版面控制時退回 HTML,這個階梯式的設計,是它二十多年來能持續被新工具採用的原因。


Sponsored Links

發佈留言