2026年9月15日·閱讀約 2 分鐘
表格標題無障礙:大多數網站遺漏的 WCAG 規則
沒有真正標題標記的資料表格,在螢幕閱讀器裡讀起來就是毫無意義的數字。瞭解 WCAG 1.3.1 的修復方法,以及 Axeazy 能與不能自動修復甚麼。
沒有真正標題標記的資料表格,在螢幕閱讀器裡讀起來就是一串光禿禿的數字,完全不知道每個數字屬於哪一行或哪一列。 修復的辦法是:標題單元格用 <th> 代替 <td>,並新增 scope 屬性。這滿足 WCAG 1.3.1(資訊和關係),讓表格從單純的視覺排版變成螢幕閱讀器真正可以瀏覽的內容。

要點
- 如果樣式相同,
<th>和<td>看起來一模一樣,但只有<th>會告訴螢幕閱讀器「這是標題」。<td>里加粗居中的文字,無論看起來如何,對輔助技術來說都不是標題。 scope屬性告訴螢幕閱讀器標題適用於哪個方向。 有效值只有col、row、colgroup和rowgroup,沒有其他。- 這是 WCAG 1.3.1(資訊和關係)的要求,A 級。 它還對應 Section 508 的 1194.22(g) 和 EN 301 549 的 9.1.3.1,因此不只是美國的規則。
- axe-core 會掃描七種不同的表格問題,其中只有一種(拼錯的
scope值)目前有自動修復。其餘的都需要一個懂得表格實際含義的人。 - 簡單表格(標題只在第一行或第一列)所需的標記比大多數指南暗示的要少。 那裡只用普通的
<th>元素就夠了;當表格在不止一個方向上有標題時,scope才變得必要。
為甚麼 <th> 與 <td> 的區別就是一切

視力正常的訪客閱讀表格時,會不假思索地掃過一行,再向上看列標題。螢幕閱讀器沒有等效的「抬眼一瞥」的辦法。它逐個單元格朗讀,而它知道某個單元格是標題而非普通資料的唯一方式,就是底層的 HTML 元素。
<th> 是標題單元格。瀏覽器預設將其加粗並居中,螢幕閱讀器在使用者瀏覽表格時會將其讀作標題。<td> 是普通資料單元格。無論對它應用甚麼 CSS,它都不會帶有這樣的提示。
幾乎所有現實中的表格都壞在這裡。開發人員做了一個表格,想讓標題行看起來加粗,於是用 <td style="font-weight: bold"> 而不是 <th>。視覺上,它與真正的標題無法區分。對螢幕閱讀器來說,它只是另一個碰巧加粗的資料單元格,與下方的單元格毫無關係。
<!-- 失敗:看起來像標題行,卻被讀作普通資料 -->
<table>
<tr>
<td><strong>Day</strong></td>
<td><strong>Open</strong></td>
<td><strong>Close</strong></td>
</tr>
<tr>
<td>Monday</td>
<td>9:00 AM</td>
<td>6:00 PM</td>
</tr>
</table>
<!-- 透過:真正的標題單元格,被讀作標題,外加表格標題說明 -->
<table>
<caption>Store hours</caption>
<tr>
<th scope="col">Day</th>
<th scope="col">Open</th>
<th scope="col">Close</th>
</tr>
<tr>
<td>Monday</td>
<td>9:00 AM</td>
<td>6:00 PM</td>
</tr>
</table>
兩者對視力正常的訪客呈現完全一樣。只有第二個能告訴螢幕閱讀器使用者,「9:00 AM」屬於 「Monday」 的 「Open」。
scope 屬性,以及甚麼時候真正需要它

對於簡單表格,也就是標題只在第一行,或只在第一列,而不是兩者都有的表格,只用 <th> 就夠了。螢幕閱讀器可以正確推斷方向。在這種情況下,WCAG 的嚴格要求其實比許多無障礙內容暗示的要輕。
一旦表格同時在兩個方向上有標題,例如日程表上方是星期、側邊是時間段,scope 在實踐中就不再是可選的了。沒有它,螢幕閱讀器沒有可靠的辦法知道某個 <th> 標註的是它所在的行還是列。
<table>
<caption>Weekly class schedule</caption>
<tr>
<th scope="col"></th>
<th scope="col">Monday</th>
<th scope="col">Wednesday</th>
</tr>
<tr>
<th scope="row">9:00 AM</th>
<td>Yoga</td>
<td>Pilates</td>
</tr>
<tr>
<th scope="row">6:00 PM</th>
<td>Spin</td>
<td>Yoga</td>
</tr>
</table>
這裡,scope="col" 標記星期標題,scope="row" 標記時間標題。螢幕閱讀器使用者移到 「Pilates」 單元格時會同時聽到兩者:Wednesday、9:00 AM、Pilates。
對於真正不規則的表格,也就是有合併單元格、標題不整齊地位於某一行或某一列的表格,僅靠 scope 是不夠的。這就是 headers 和 id 屬性的用途:每個資料單元格明確列出適用於它的每個標題單元格的 id。
<th id="q3">Q3</th>
...
<td headers="q3">42</td>
這種寫法編寫和維護都更費功夫,這正是它只保留給 scope 確實無法描述的表格、而不作為預設做法的原因。
axe-core 究竟檢查表格的哪些方面
axe-core 就是 Chrome DevTools 無障礙面板和 Axeazy 掃描器背後的同一個引擎,它對錶格標記執行七項獨立檢查。目前只有一項有自動修復。
| 規則 | 檢查內容 | 修復路徑 |
|---|---|---|
scope-attr-valid |
scope 的值不是真正的單詞,是 col/row/colgroup/rowgroup 的拼寫錯誤或複數 |
透過 GitHub pull request 自動修復,範圍很窄:只處理可識別的拼寫錯誤 |
empty-table-header |
存在 <th> 但裡面沒有文字 |
手動 |
th-has-data-cells |
存在 <th> 但沒有任何資料單元格使用它 |
手動 |
td-has-header |
某個資料單元格完全沒有關聯的標題 | 手動 |
td-headers-attr |
headers 屬性指向的 id 不是真正的標題單元格 |
手動 |
table-duplicate-name |
同一頁面上的兩個表格具有相同的可訪問名稱 | 手動 |
table-fake-caption |
文字被設定成看起來像標題說明,而不是真正的 <caption> 元素 |
手動 |
這張表讓真實情況一目瞭然。表格結構絕大部分屬於手動修復的類別。唯一自動寫入的部分,是更正已經存在但拼錯的 scope 值,比如把 "cols" 或 "ROW " 規範化為 "col" 或 "row"。新增缺失的標題、編寫表格標題說明,或確定哪個 headers 的 id 屬於哪個單元格,都需要理解表格的實際含義,這仍然是人的工作。
如何檢查您自己的表格
您不需要安裝螢幕閱讀器就能發現這個錯誤最常見的形式。
- 檢視頁面原始碼。 右鍵點選網站上的任意表格,選擇「檢視頁面原始碼」,或開啟 DevTools 檢視 Elements 面板。搜尋
<th。如果看起來像標題的那一行是由<td>元素構成的,這個表格就不透過。 - 檢查多方向表格上的
scope值。 如果表格同時有橫向在上方和縱向在側邊的標題,請確認每個<th>都帶有scope="col"或scope="row",而不只是加粗樣式。 - 聽一聽。 在 NVDA 中,用表格導航(
Ctrl+Alt+方向鍵)在標記正確的表格中移動時,會在每個單元格的值旁讀出相關標題。如果您只聽到沒有先讀標題的原始數字,說明表格沒有被正確關聯。 - 或者執行掃描,而不是逐個表格檢查。 Axeazy 的免費掃描大約 60 秒就能按上述全部七條規則檢查您首頁上的每個表格,同時涵蓋它支援的其他修復類別。
常見錯誤
- 用加粗的
<td>單元格代替<th>。 最常見的失敗,也最難靠肉眼發現,因為它看起來完全正確。 - 表格標題說明只是表格上方一行加粗的文字,而不是真正的
<caption>元素。視力正常的訪客看不出區別,螢幕閱讀器卻能。 - 同一頁面上的多個表格沒有區分性的標題說明,導致螢幕閱讀器使用者在表格之間跳轉時分不清哪個是哪個。
- 僅為視覺排版而使用表格,而不是用於表格資料。螢幕閱讀器仍會嘗試讀出本不該存在的行列關係,這比完全沒有結構更令人困惑。現代 CSS(Grid 或 Flexbox)可以處理排版,沒有這種副作用。
- 在表格實際需要
headers/id時卻使用scope。scope只能描述簡單的行或列關係。有合併單元格或標題不整齊位於某一行或某一列的表格,需要更明確的headers/id配對。
Axeazy 在這裡能修復甚麼

這一類別比大多數更適合坦率地談,因為其中自動化的部分確實很小。
Axeazy 的掃描一旦發現上述七條表格規則的問題就會標記出來,無論是 Axeazy、Chrome DevTools,還是任何基於 axe-core 的工具,檢測結果都是一樣的。寫出修復內容才是需要手動的地方。目前唯一能進入真實 GitHub pull request 的表格相關修復,是更正已存在的、屬於可識別拼寫錯誤或複數的 scope 值,該類別中的其他任何問題都還沒有自動化路徑。
目前 WordPress 外掛也完全沒有處理表格修復的途徑。免費外掛的三項即時修復涵蓋跳過導航、語言屬性和替代文字後備,都不涉及表格標記,付費方案目前也沒有擴充套件到表格結構。
這不是有人遺忘的缺口。判斷某個 <td> 是否本應是 <th>,或者一個不規則單元格究竟屬於哪個標題,需要理解表格想要表達甚麼。指令碼在這裡猜錯,會悄悄地向恰恰依賴標記來理解資料的那些人歪曲資料,這比標記出來交給人正確修復更糟。檢視完整的修復類別說明。
常見問題
每個標題單元格都需要 scope 屬性嗎?
不需要。對於標題只在第一行或只在第一列的簡單表格,普通的 <th> 元素本身就足夠了。當表格同時在兩個方向上有標題時,scope 才變得必要,比如上方是星期、側邊是時間的日程表。
scope 與 headers/id 有甚麼區別?
scope 描述簡單的單方向關係:一個標題適用於整行、整列,或一組行或列。headers/id 更明確:每個資料單元格透過 id 精確列出哪些標題單元格適用於它。規則的網格狀表格用 scope,只有帶合併單元格或標題不整齊位於某行某列的不規則表格才用 headers/id。
Axeazy 會自動修復缺失的表格標題嗎?
大多數不會,值得坦率地說明。目前表格相關修復中唯一有可用自動路徑的,是更正已存在但拼錯的 scope 值。新增缺失的標題、編寫真正的表格標題說明,或把 headers 對映到正確的 id,都需要理解表格的含義,因此它們仍屬於手動稽核項。
每個表格都需要表格標題說明(caption)嗎?
它本身並非 WCAG 1.3.1 的嚴格要求,但確實有用,尤其是當頁面上有不止一個表格時。表格標題說明為表格提供可訪問名稱,讓在表格之間跳轉的螢幕閱讀器使用者知道自己到了哪一個。
用於頁面佈局而不是資料的表格呢?
儘可能避免。螢幕閱讀器仍會嘗試讀出佈局表格上的行列關係,造成用純 CSS 佈局時不會有的困惑。如果遺留的佈局表格無法立即移除,給它加上 role="presentation" 可以讓輔助技術完全跳過表格語義。
參考來源
我們交付的每份報告的範圍: 範圍限制:本報告記錄的是使用 axe-core v4.11.0 進行 WCAG 2.2 AA 自動掃描所發現的違規問題。自動化工具無法測試所有 WCAG 準則;許多準則需要人工審查。本報告不構成法律意見,不保證符合 ADA,亦不能防止法律行動。是否符合 ADA 是由法院作出的法律裁定。如需完整的 WCAG 合規評估,請聘請獲 IAAP 認證的無障礙專業人士。