六個 ATX 階層
- 標題共有六階,用一到六個井字號書寫,最後一個井字號後面的空格是必要的。
- 一份文件只放一個 H1,也不要跳階,因為螢幕閱讀器與爬蟲都把標題讀成一棵樹。
- 每個標題都會自動拿到錨點 ID:轉小寫、移除標點、空格換成連字號。
- 緊貼文字底下的一排連字號不是分隔線 - 它會把上面那行變成 H2。
標題的寫法是:行首放一到六個井字號、一個空格,然後是文字。這叫 ATX 語法,也是現在幾乎所有人採用的寫法:
# 發佈說明
## 版本 2.4
### 錯誤修正
#### 解析器
##### 邊界情況
###### 已知退步
這六行分別變成 <h1> 到 <h6>。HTML 只到第六階,所以七個井字號不是標題,會原樣顯示成文字。
井字號後面的空格是必要的
這是標題最常見的失敗原因。#發佈說明 是段落,# 發佈說明 才是標題。CommonMark 與 GitHub 風格 Markdown 都要求最後一個井字號後面有空格或 Tab。最初的 Markdown.pl 對這點很寬鬆,少數老舊渲染器至今仍然如此,舊檔案才會在某個工具裡正常、換一個就壞掉。
結尾井字號、行首空白與跳脫
標題後面可以再加一串井字號收尾。它純屬裝飾,長度隨意,不必跟開頭一致:
## 版本 2.4 ##
## 版本 2.4 ###########
兩行都得到 <h2>版本 2.4</h2>,但結尾那串前面一定要有空格。寫成 ## 版本 2.4##,標題文字就會變成「版本 2.4##」。
開頭井字號前面最多三個空白會被忽略,第四個就讓整行變成縮排式程式碼區塊,井字號原樣呈現。想讓一行真的以井字號開頭就跳脫它:\# 這不是標題。只想快速查六個階層的樣子,看一頁式語法參考就夠了。
小提醒:標題怎麼都渲染不出來時,先數行首的空格再查其他原因。四個空格就是縮排式程式碼區塊,而行首空白在多數編輯器裡完全看不出來。
Setext 標題與破折號底線的陷阱
Markdown 還有一種更古老的第二語法:在文字底下畫一排等號代表第一階,畫一排連字號代表第二階。
發佈說明
=============
版本 2.4
-----------
這叫 Setext 標題。底線一個字元就夠了,= 和 =========== 意思相同,長度也不必跟標題文字對齊。它的標題文字甚至可以跨多行,這是 ATX 做不到的。
它只有兩個階層
Setext 沒有對應 H3 到 H6 的寫法,用它起頭的文件只要需要第三階就得改回井字號。包含 Prettier 在內的多數格式化工具也都會把它改寫成 ATX。新文件請一律用井字號。
人人都踩過的陷阱
因為文字底下那排連字號會產生 H2,下面這段的結果跟外觀完全不同:
部署完成後執行冒煙測試。
---
下一段從這裡開始。
作者想要的是一條分隔線,實際得到的卻是一個裝著整句話的 H2。加一行空行就修好了,連字號與上方文字切開後才會被讀成分隔線:
部署完成後執行冒煙測試。
---
下一段從這裡開始。
兩個習慣可以讓它不再發生:
- 分隔線一律寫成
***或___,這兩種永遠不會被誤認成標題底線。 - 記得 Jekyll、Hugo 與 Astro 的 YAML front matter 同樣用
---包起來,而它只有在檔案最開頭才算 front matter。
階層規則:只用一個 H1,也不要跳階
標題階層不是字級大小,而是一棵巢狀結構樹,輔助科技與搜尋引擎都這樣讀它。
一份文件只用一個 H1
H1 是這一頁的標題,代表整份文件在講什麼。放兩個 H1 等於告訴螢幕閱讀器這頁裝了兩份文件。很多靜態網站產生器已經會從 front matter 的標題輸出 H1,這時 Markdown 內文應該從 H2 開始,動手前先看一眼渲染出來的 HTML。
不要跳過階層
因為覺得字比較小好看,就從 ## 直接跳到 ####,會把大綱弄壞。代價出現在三個地方:
- 螢幕閱讀器導覽。使用者靠叫出標題清單瀏覽頁面,也常用「跳到同階的下一個標題」移動;少掉一階,那個 H4 就沒有父標題了。
- 無障礙檢測。自動化工具會直接標記它,它也違反 WCAG 1.3.1「資訊與關聯性」。
- 搜尋。爬蟲用標題樹判斷哪一段回答哪一個問題,精選摘要也仰賴這個結構。
字級不順眼就用 CSS 調整,階層本身請保持誠實。把草稿丟進目錄產生器跑一次,就會看到自己實際寫出來的大綱,缺的階層也一併現形。
| Markdown | HTML | 典型用途 | 標題範例 | 產生的 ID |
|---|---|---|---|---|
# | <h1> | 頁面標題,只用一次 | # Markdown Style Guide | #markdown-style-guide |
## | <h2> | 主要章節,目錄採用的階層 | ## Getting Started | #getting-started |
### | <h3> | 章節內的子主題 | ### Install the CLI | #install-the-cli |
#### | <h4> | API 條目、個別選項說明、邊界情況 | #### Windows notes | #windows-notes |
##### | <h5> | 少見,只出現在很深的參考文件 | ##### Return values | #return-values |
###### | <h6> | 更少見,通常代表這頁該拆開了 | ###### Legacy flags | #legacy-flags |
文字 + === | <h1> | Setext 第一階,舊檔案才會看到 | Release Notes | #release-notes |
文字 + --- | <h2> | Setext 第二階,舊檔案才會看到 | Version 2.4 | #version-24 |
標題 ID 與錨點連結是怎麼產生的
在 GitHub、GitLab 與絕大多數文件網站上,每個標題都會被默默加上一個 id,這正是你能連到一份長 README 中段的原因。這個 slug 由標題文字經過一段簡短流程轉出來:
## Setting Up the API Key (v2.1)!
1. 去掉行內語法 -> Setting Up the API Key (v2.1)!
2. 全部轉小寫 -> setting up the api key (v2.1)!
3. 移除標點 -> setting up the api key v21
4. 空格換連字號 -> setting-up-the-api-key-v21
所以錨點是 #setting-up-the-api-key-v21。注意 2.1 的下場:小數點屬於標點,被移除後只剩 v21,憑記憶猜正是錨點壞掉的典型過程。行內格式同樣會被剝掉,所以 ### The **important** part 得到的是 #the-important-part。
重複的標題會加上數字後綴
## Installation -> #installation
## Configuration -> #configuration
## Installation -> #installation-1
## Installation -> #installation-2
這就是「上個月還好好的連結,現在跳到錯誤章節」的原因:有人在前面新增了同名標題,後面每個後綴整批位移一位。重複的標題請加上足以區分的字眼。
連到某個標題
開始之前請先看[安裝步驟](#setting-up-the-api-key-v21)。
[安裝步驟](docs/setup.md#setting-up-the-api-key-v21)
相對路徑、參考式連結與跳脫規則都在連結參考裡。跳轉連結沒反應時,不要花時間推敲 slug 規則:打開渲染後的頁面,把滑鼠移到標題上,直接從連結圖示複製錨點。
小提醒:想把這些 ID 一次變成整份目錄,把文件貼進目錄產生器就好。它套用的正是上面這套 slug 規則,產出的錨點就是渲染器會建立的那些。
手動把 ID 釘死
Python-Markdown、kramdown、Pandoc 與 MkDocs 還允許你在標題尾端加 {#api-key} 把 ID 釘死,GitHub 則會把大括號原樣印出來。在 GitHub 上請改用標題正上方的 <a id="api-key"></a>,因為 Markdown 本來就接受原始 HTML。
引言、清單與段落裡的標題
標題是區塊元素,任何能容納區塊的地方都放得下它。
放在引言區塊裡
> ## 停用通知
>
> v1 端點將於三月停止回應。
每一行前面都要加大於符號,標題那行也不例外。它一樣會拿到 ID,也一樣會出現在自動產生的目錄裡。巢狀引言與建立在引言之上的提示框語法,請見引言區塊參考。
放在清單項目裡
把標題縮排到項目的文字欄位,上面留一行空行:
1. 準備機器
### 系統需求
Node 20 以上,以及 2 GB 可用磁碟空間。
2. 執行安裝程式
這樣寫得出來,但請三思。清單裡的標題會在大綱中佔一個位置,視覺上卻像個子項目,而且會讓清單變成鬆散清單,改變每個項目的行距。那個位置通常用粗體更合適,見粗體與斜體參考;巢狀內容的縮排規則則在清單參考。
上面沒有空行的標題
CommonMark 與 GFM 允許 ATX 標題直接插斷段落,所以下面這段會渲染成一個段落加一個 H2:
建置在 40 秒內完成。
## 下一步
比較舊的引擎沒這麼寬容,有些會把標題吞進段落裡,井字號原樣印出來。Setext 的行為又不一樣,因為緊貼段落底下的連字號會被讀成底線。
注意:不管渲染器允許什麼,每個標題上方都請留一行空行。下方的空行不是必要的,但幾個月後回頭看原始檔時,你會慶幸自己有留。
表情符號、中文字與標題該多長
表情符號
標題裡放表情符號可以正常渲染,直接貼上或在 GitHub 上用 :rocket: 這類短碼都行。麻煩的是 ID:產生 slug 時表情符號會被移除,留下的空格變成連字號,所以開頭的表情符號會產生一個以連字號起頭的錨點。
## 🚀 快速上手 -> #-快速上手
這種錨點可以用,只是手寫時看起來很怪。把表情符號改放在文字後面,或直接從渲染後的頁面複製。
中文、日文與韓文
中日韓文字在 GitHub 上會完整保留,所以 ## 安裝步驟 的 ID 就是 #安裝步驟。從網址列複製出來會看到百分號編碼,這是正常的,也一樣有效。靜態網站產生器就不太一致:
- 有的和 GitHub 一樣原樣保留中文字。
- 有的轉成拼音或羅馬字。
- 也有少數直接放棄,退回
#section-1。
先測一個錨點再動手寫五十個。全形標點跟半形標點一樣會被移除,所以 ## 安裝步驟(進階) 的 ID 是 #安裝步驟進階。
長度
標題請控制在大約三十個中文字以內。太長的標題在側邊欄與目錄裡會難看地折行,產生冗長的錨點,被搜尋引擎擷取時也會被截斷。把重要的詞放前面:「設定單一登入」勝過「關於如何為你的團隊設定單一登入的一些筆記」。
常見錯誤與修正寫法
1. 井字號後面沒有空格。那一行仍然是段落,井字號原樣印出來。錯誤與正確寫法:
#簡介
# 簡介
2. 想畫分隔線卻變成標題。緊貼文字底下的連字號會把上面那行變成標題。錯誤寫法:
設定到這裡告一段落。
---
加一行空行就修好了,或直接把分隔線寫成 ***:
設定到這裡告一段落。
---
3. 為了視覺效果跳階。下面是壞掉的大綱與修正版,覺得字太大就用 CSS 調小:
## 設定
#### 環境變數
## 設定
### 環境變數
4. 用粗體假裝標題。這對文件大綱、螢幕閱讀器的標題導覽與所有目錄產生器都是隱形的,而且產生不出可以連過去的 ID。錯誤與正確寫法:
**環境變數**
### 環境變數
5. 照著標題文字手打錨點。大寫、空格與標點都不保留。錯誤與正確寫法:
[跳過去](#Setting Up the API Key (v2.1))
[跳過去](#setting-up-the-api-key-v21)
標題怎麼調都不對時,把它單獨貼進編輯器,上下各留一行空行。如果那樣渲染正常,問題就出在上下文:某個縮排、少掉的空行,或它被困在清單項目裡。Markdown 完整指南把標題與其他元素依序串成一份文件;Markdown 是什麼解釋了這個格式為何如此在意空行;程式碼區塊與圖片參考則涵蓋標題底下最常出現的東西。
相容性資料驗證日期
常見問題
Markdown 標題有幾個階層?
六個,用一到六個井字號書寫,分別對應 <h1> 到 <h6>。七個以上的井字號不是標題,會原樣顯示成文字。另一種 Setext 語法(在文字底下畫 = 或 -)則只有前兩階。
為什麼我的 Markdown 標題沒有渲染?
幾乎都是少了空格:#標題 是段落,# 標題 才是標題。另外兩個原因是行首有四個以上的空白(那一行會變成程式碼區塊),以及比較嚴格的渲染器要求標題上方留一行空行。補上空格與空行就會正常。
一份 Markdown 文件只能有一個 H1 嗎?
是的。H1 是文件標題,出現第二個等於告訴螢幕閱讀器與爬蟲這一頁裝了兩份文件。如果你的靜態網站產生器已經從 front matter 渲染出標題,Markdown 內文請從 ## 開始,避免整頁出現兩個 H1。
Markdown 標題的錨點 ID 是怎麼產生的?
文字會全部轉小寫、移除標點、把空格換成連字號,所以 ## Setting Up the API Key (v2.1)! 的 ID 是 #setting-up-the-api-key-v21。重複的標題會依序加上 -1、-2。與其手打,不如從渲染後標題旁的連結圖示複製,或交給目錄產生器一次寫好。
為什麼我打的三個連字號變成標題而不是分隔線?
因為緊貼在一行文字底下的連字號是 Setext 的第二階標題語法,上面那行文字就被變成 H2 了。在文字與連字號之間加一行空行,或把分隔線一律寫成 ***,後者永遠不會被讀成標題底線。
Markdown 要怎麼加一條水平分隔線?
單獨一行打三個以上的連字號、星號或底線就行,---、***、___ 畫出來的都是同一條 <hr> 分隔線。上方記得留一行空行。少了那行空行,緊貼在文字下方的 --- 會被當成 Setext 底線,把上面那行文字變成標題,而不是畫線。養成寫 *** 的習慣就完全不會撞到這個問題,其他區塊級符號則整理在語法速查表裡。
延伸閱讀
立即使用編輯器
立即使用編輯器