什麼是 GFM?它如何成為業界標準

重點摘要
  • GFM 是 GitHub 的 Markdown 方言,2017 年正式發佈,定義為 CommonMark 的嚴格超集合。
  • 規格本身只多五樣東西:表格、待辦清單、刪除線、裸網址自動連結,以及原始 HTML 過濾。
  • 警示框、@提及、表情符號代碼、註腳與 Mermaid 來自 GitHub 的渲染器,不在規格之內。
  • 預設就寫 GFM。在不支援的地方它會退回純文字,不會把整頁弄壞。

GitHub 風格 Markdown(GitHub Flavored Markdown,簡稱 GFM)是 GitHub 平台全面採用的 Markdown 方言。README、Issue、Pull Request、留言、Wiki、Gist 全都靠它運作。GFM 保留原始 Markdown 語法,再補上技術寫作者長年期盼的功能:表格、待辦清單、刪除線,以及網址自動連結。

GFM 如何變成預設選擇

它的歷史正好解釋了它的影響力。GitHub 於 2008 年上線、2009 年採用 Markdown,當時 2004 年的語法說明相當鬆散,同一份文件在兩套解析器下可能長得不一樣。GitHub 就在上面疊加自家擴充功能。每天有數百萬名開發者在 GitHub 上寫 README,GitHub 的版本於是悄悄變成大家實際學會的版本。

2017 年,GitHub 把一切釘死,正式發佈 GFM 規格書。那是一份嚴謹、經過完整測試的文件,定義為 CommonMark 的嚴格超集合。任何合法的 CommonMark 文件在 GFM 下的渲染結果完全相同,GFM 只是額外定義了一組固定而明確的擴充功能。

除了 GitHub,哪裡也吃 GFM

精確的規格書,加上全球最大的程式碼託管平台,這個組合很難被超越。核心擴充功能現在幾乎到處都能用:

  • 程式碼託管:GitHub、GitLab、Bitbucket。
  • 編輯器與筆記:Obsidian、Typora、VS Code 的預覽功能。
  • 聊天與知識庫:Discord、Notion。
  • 發佈工具:Hugo 以及多數現代靜態網站產生器。

所以當有人說「用 Markdown 寫就好」,他指的幾乎一定是 GFM。如果你對 Markdown 本身還不熟,建議先讀我們的 Markdown 完整教學再回來。如果你還在猶豫該用哪一層來寫,Markdown 與 HTML 的比較會把這個問題講清楚。

插圖:一份純 Markdown 文件延伸出包含表格、核取方塊與圖表的擴充版本

表格:用純文字呈現結構化資料

表格是原始 Markdown 最令人想念的功能。直線符號(|)分隔欄位,一列由連字號組成的分隔線區分表頭與內容,分隔線裡的冒號則決定對齊方式。

| 功能     | 原始 Markdown | GFM |
|:---------|:------------:|----:|
| 表格     |      無      | 有  |
| 待辦清單 |      無      | 有  |
| 刪除線   |      無      | 有  |

分隔線如何決定對齊

對齊全靠那一列。把冒號想成磁鐵,文字會被吸過去:

  • :--- 或單純的 --- 是靠左對齊,也是預設值。
  • :---: 置中,適合「有/無」這類短短的狀態字。
  • ---: 靠右,數字與金額用這個最好讀。

直線符號在原始碼裡不必對得整整齊齊,解析器只在乎符號有沒有出現。但排列整齊還是值得多按幾下空白鍵,因為下一個編輯這份檔案的人,看到的是純文字。

GFM 表格的極限在哪裡

這套語法刻意做得很小。不能合併儲存格、不能巢狀表格,儲存格裡也放不了真正的換行。要顯示直線符號本身,得寫成 \|,否則會被當成欄位邊界;要在儲存格內換行,就得改用 <br> 標籤。

表格也是實務上最常出包的結構。跳脫規則、產生器,以及什麼時候該乾脆改用 HTML 表格,Markdown 表格指南都有完整說明。

待辦清單:在文件裡放核取方塊

待辦清單就是一般的項目清單,只是每一項以 [ ](未完成)或 [x](已完成)開頭。成敗取決於兩個空格:空方括號裡面要有一個,右方括號後面也要有一個。

## 發佈檢查清單

- [x] 更新變更記錄
- [x] 調升版本號
- [ ] 建立版本標籤
- [ ] 發佈版本說明
    - [ ] 巢狀子任務也支援

在 GitHub 上可以直接點選

待辦清單最強的地方,是它可以是互動的。在 Issue、Pull Request 描述與留言中,渲染出來的核取方塊可以直接點。你打勾的同時,GitHub 會替你改掉底層的 Markdown 原始碼。它還會顯示進度,例如 Issue 列表和引用該 PR 的地方都會出現「3 of 5 tasks」。Notion、Obsidian 和許多待辦事項應用程式,也把相同語法當成可點選的核取方塊。

其他地方是唯讀的方塊

在靜態輸出裡,方塊照樣會渲染出來,只是不能點。README、部落格文章、匯出的 HTML 檔都屬於這一類。發佈一份檢查清單仍然是對讀者最清楚的做法,因為他們可以直接複製原始碼再利用。

子任務走的是一般清單的縮排規則,所以一般清單的陷阱也照樣成立:子項目要縮排到父項目的文字下方,而且千萬不要把 Tab 和空格混著用。各家渲染器到底期待幾個空格,Markdown 清單語法寫得很清楚。

GitHub 平台專屬功能:警示框、提及、註腳、Mermaid

正式的 GFM 規格之外,GitHub 自家的渲染器還加了一層平台功能。有些只在 GitHub 上有效;有些,例如註腳與 Mermaid,如今在別處也走得相當順。

警示框:五種彩色提示方塊

警示框是用引用區塊語法做出來的提示方塊。引用的第一行寫上類型,GitHub 就會給它專屬的顏色與圖示:

> [!WARNING]
> 此操作將永久刪除你的資料。
  • [!NOTE] - 讀者略讀時也不該跳過的資訊。
  • [!TIP] - 可有可無、但能讓事情更順的小撇步。
  • [!IMPORTANT] - 沒看到就做不成功的關鍵資訊。
  • [!WARNING] - 需要立刻注意的風險。
  • [!CAUTION] - 某個動作可能造成的不良後果。

警示框是疊在規格之上的功能,不在規格裡面。在其他工具中它會退回成普通的引用區塊,一樣讀得懂。它借用的語法,包括巢狀與空行規則,都收在引用區塊語法那一頁。

@提及、Issue 與 commit 參照

輸入 @使用者名稱 會連到該使用者的個人頁面並發出通知。輸入 #123 會連到同一個儲存庫的第 123 號 Issue 或 Pull Request,直接貼上 commit 的 SHA 值也會連到那次提交。這些功能讓 GitHub 上的討論緊密串連,同時也是本頁最帶不走的一組語法:在其他渲染器裡,它們只是普通文字。

表情符號代碼

在冒號之間打上名稱,GitHub 就會換成圖案。:tada: 變成 🎉、:rocket: 變成 🚀、:bug: 變成 🐛。GitHub 支援數百個這類代碼,Discord 與 Slack 也採用相同慣例,習慣可以直接沿用。

註腳

註腳分成兩部分:句子裡的參照標記,以及可以放在檔案任何位置的定義。正文寫 某個論點。[^1],另外再加一行 [^1]: 資料來源。GitHub 會把所有定義集中到頁面底部,並自動補上返回連結。標籤可以用文字而不用數字,註腳語法指南非常推薦這個習慣。

Mermaid 與語法上色的程式碼區塊

在開頭圍欄後加上語言名稱 - ```python```js```bash - 整個區塊就會依該語言上色。把圍欄標成 mermaid,GitHub 還會更進一步:把內容渲染成即時圖表,而且像其他文字一樣受版本控制。下一節會完整說明這兩件事。

插圖:程式碼託管介面上顯示彩色警示框、表情符號、使用者提及與流程圖

程式碼區塊的語法上色

圍欄式程式碼區塊就是三個反引號、你的程式碼,再三個反引號,中間的內容會原封不動保留。真正讓那個灰色方塊變成彩色程式碼的,是語言代碼:緊接在開頭圍欄之後、中間不留空格的一個短字。

```python
def greet(name):
    print(f"Hello, {name}")
```

```js
const greet = (name) => console.log(`Hello, ${name}`);
```

GitHub 靠開源的語言辨識函式庫 Linguist 決定怎麼上色,也就是替每個儲存庫畫出語言比例條的那個元件。Linguist 認得數百種語言以及它們常見的別名,所以 pypython 會導向同一組上色規則。

萬一你寫了它不認得的代碼,不會壞掉,也不會跳出錯誤。那個區塊只會降級成普通的等寬程式碼區塊,就像你根本沒寫語言代碼一樣。圍欄還有幾條值得知道的規則,都整理在程式碼區塊語法那一頁。

你真正會用到的語言代碼

語言代碼別名適用場合
pythonpyPython 腳本與程式片段
javascriptjs瀏覽器與 Node.js 程式碼
typescriptts帶型別的 JavaScript、型別定義檔
bashshshell終端機指令與安裝步驟
jsonAPI 回應、設定檔、套件清單
yamlymlCI 流程、Docker Compose、front matter
html標記範例與樣板
css樣式表與選擇器範例
sql查詢語法、資料表結構、遷移腳本
diffpatch呈現前後差異、程式碼審查建議
plaintexttexttxt輸出、log,以及任何不想上色的內容

diff 區塊比文字描述更清楚

diff 值得單獨學起來。行首加 + 代表新增、加 - 代表刪除,GitHub 會把它們分別染成綠色與紅色:

```diff
- const port = 3000;
+ const port = process.env.PORT || 3000;
```

刻意關掉上色

另一個極端是 text,也可以寫成 plaintext。它的任務就是把上色關掉。終端機輸出、log 片段、目錄樹、ASCII 圖,都該用它。把上色器放進這些內容裡,它只會硬套上根本不存在的語法。

上色是渲染器的功能,不是 Markdown 的功能

這一點比表格裡任何一個代碼都重要。CommonMark 與 GFM 規格都沒有規定圍欄一定要上色。規格只說圍欄後面那串文字是「資訊字串(info string)」,渲染器可以自行運用。

實務上,那串文字會變成 <code> 元素上的 class="language-python",接著由樣式表或上色函式庫接手。所以結果會因工具而異:

  • GitHub 與 GitLab 會直接替你上色。
  • 純 CommonMark 解析器不會,它本來也沒答應過要上色。
  • 靜態網站產生器要先接上 Prism、highlight.js 或 Chroma 才會上色。

我們自己的線上編輯器也會上色,用的是 highlight.js,而且只在文件真的含有程式碼時才載入。有標語言代碼的圍欄會上色;沒標的則刻意維持素色,因為猜錯語言只會把程式碼染成錯的顏色。

小提醒:每個圍欄都標上語言代碼,連放終端機輸出的也一樣。寫 text 等於告訴下一個讀者「這塊本來就不該上色」,也避免日後某個工具猜錯。

用一般圍欄畫出 Mermaid 圖表

Mermaid 是 GitHub 對資訊字串最搶眼的運用。把圍欄標成 mermaid,GitHub 完全不會上色,而是把內容渲染成一張真正的圖:

```mermaid
graph TD;
  A[撰寫 Markdown] --> B[提交];
  B --> C[GitHub 渲染成圖表];
```

流程圖、時序圖、類別圖、狀態圖、甘特圖都能這樣寫。每一張都以純文字存在儲存庫裡,也像其他檔案一樣可以做版本比對。GitLab、Notion、Obsidian 同樣支援 Mermaid;不支援的渲染器則單純顯示成一般程式碼區塊。

上面那段不用離開本站就能試。把它貼進線上編輯器,預覽窗格就會把圖畫出來。萬一 Mermaid 語法打錯,那個圍欄會維持成程式碼區塊,不會跳錯誤訊息,所以寫到一半的圖不會拖垮整個預覽。

數學公式:$ 與 $$

GitHub 同樣支援 LaTeX 風格的數學式。行內公式放在單個錢字號之間,例如 $E = mc^2$;獨立展示的公式則放在各自成行的兩個錢字號之間:

$$
\frac{1}{n}\sum_{i=1}^{n} x_i
$$

GitHub 會在 README、Issue、留言與 Wiki 中用 MathJax 渲染這些公式。一般文句裡的錢字號可能被誤判成公式起點,所以要顯示錢字號本身時請寫成 \$。數學公式和語法上色一樣依賴渲染器:GitHub、Obsidian、Typora 與 Pandoc 都支援,純 CommonMark 解析器則會把錢字號原樣印出來。

本站的線上編輯器也會渲染數學公式,用的是 KaTeX。它接受 $行內$$$展示$$,也接受 LaTeX 使用者習慣打的 \(...\)\[...\]。所以你可以先在這裡確認公式排出來對不對,再貼進 README。

GFM、CommonMark 與原始 Markdown 的差異

這三個名字經常被搞混,先把族譜理清楚:

  • 原始 Markdown(2004)是 John Gruber 寫的 Perl 腳本,加上一份非正式的語法說明。開創性十足,但模糊到讓各家解析器為了邊界情況爭論了十年。
  • CommonMark(2014)是嚴謹的標準化計畫。它用正式規格與數百個測試案例把每一處歧義釘死,而且刻意不新增任何功能。
  • GFM(2017 年定稿)是 CommonMark 加上 GitHub 的擴充功能。這也是為什麼能解析 GFM 的工具,一定也能完美解析 CommonMark。

逐項比較

功能原始版(2004)CommonMarkGFM
標題、清單、連結、強調
正式規格+測試套件
表格
待辦清單
刪除線
裸網址自動連結
原始 HTML 標籤過濾

那到底該寫哪一種?

直接寫 GFM。它的降級表現很優雅:表格在只支援 CommonMark 的渲染器裡,頂多顯示成幾條直線符號,而不是壞掉的頁面。而且 GFM 正是你的同事、你的工具,還有未來的你最可能預期的方言。

例外情況是你無法掌控、也無法測試的目的地。不確定對方支援到哪裡時,就守住標題、清單、連結與強調這四樣,每種方言的處理方式都一致。我們的線上編輯器提供完整的 GFM 即時預覽,README、Issue 留言或 Wiki 頁面都能在發佈前先看清楚。

相容性資料驗證日期

常見問題

GFM 與一般 Markdown 相容嗎?

相容。GFM 被定義為 CommonMark 的嚴格超集合,而 CommonMark 又涵蓋原始 Markdown 的全部核心語法。任何標準 Markdown 文件在 GFM 下都能正確渲染;反過來就不一定了,因為表格、待辦清單等 GFM 專屬功能需要支援 GFM 的渲染器。

GFM 的表格和待辦清單在 GitHub 以外的地方能用嗎?

大多可以。GitLab、Bitbucket、Obsidian、Typora、VS Code 預覽、Hugo 以及多數現代渲染器都支援 GFM 的核心擴充功能。通常「帶不走」的是:@提及、#123 Issue 參照,以及可點選(互動式)的核取方塊 - 這些依賴 GitHub 平台本身。

如何在 GFM 中加入提示框或警告框?

使用警示框語法:在引用區塊的第一行寫 [!NOTE][!TIP][!IMPORTANT][!WARNING][!CAUTION],GitHub 會渲染成帶顏色與圖示的提示框。注意警示框是 GitHub 疊加在 GFM 規格之上的平台功能,部分其他渲染器只會顯示成普通的引用區塊。

為什麼我的 HTML 在 GitHub README 裡失效?

基於安全考量,GFM 會過濾特定的危險標籤 - <script><style><iframe><textarea> 等。無害的標籤如 <details><sub><br> 仍然有效。如果排版用的 HTML 看起來被忽略,也請確認它沒有被包在程式碼區塊裡。

發佈前可以在哪裡測試 GFM 語法?

我們的免費線上 Markdown 編輯器會即時渲染 GFM - 表格、待辦清單、刪除線、程式碼區塊等 - 讓你在貼進 GitHub 之前就確認 README 或 Issue 留言的效果。你輸入的內容完全不會離開瀏覽器。

CommonMark 是什麼?

CommonMark 是一份正式規格,總算把「Markdown 到底代表什麼意思」定義清楚。Gruber 在 2004 年寫的語法說明是散文形式,同一份檔案在兩套解析器下可能出現兩種結果;2014 年的規格用精確的規則加上數百個測試案例取代它,而且刻意不新增任何功能。GFM 被定義為它的嚴格超集合,所以任何合法的 CommonMark 檔案在 GitHub 上的渲染結果完全一致。這段故事的其餘部分都寫在什麼是 Markdown

Markdown 可以打表情符號嗎?

可以。直接把 Unicode 表情符號貼進檔案就行,到哪裡都顯示得出來,因為對 Markdown 來說它就跟其他文字沒兩樣。至於 :tada: 這種冒號代碼寫法就是另一回事了:那是平台功能,不是 Markdown 語法。GitHub、GitLab、Discord 和 Slack 會自動換成圖案,純 CommonMark 則會把冒號原樣留在畫面上。

Markdown 的 Mermaid 是什麼?

Mermaid 讓你在標成 mermaid 的圍欄區塊裡,用純文字描述一張圖,再由渲染器把圖畫出來。GitHub 和 GitLab 會直接渲染成流程圖、時序圖或甘特圖,所以圖表能以文字形式存在儲存庫裡,跟其他檔案一樣做版本比對。其他多數渲染器只會顯示原始的 Mermaid 程式碼,因為這是渲染器的功能,不是 Markdown 語法,圍欄本身就只是一個貼了標籤的普通程式碼區塊

延伸閱讀

立即使用編輯器

立即使用編輯器