真正有幫助的 ARIA 標籤開發者指南
ARIA 標籤不是神奇的無障礙層。用得好,它們能讓控制項更容易理解;用得隨意,則會隱藏有用文字,並造成令人困惑的介面。
目錄
ARIA 標籤是用來命名,不是用來道歉
ARIA 很有用,但它經常被拿來修補不清楚的 HTML。這正是團隊容易出問題的地方。
最常見的例子是 aria-label。它看起來無害:加上一段字串、讓 linter 通過,然後繼續往下做。但無障礙名稱不是裝飾。它是許多輔助科技在使用者透過按鈕、連結、表單欄位、標題、地標與控制項導覽時,呈現給使用者的名稱。
如果這個名稱含糊、重複、過時,或與可見標籤不同,介面就會變得更難使用。有時甚至更糟:aria-label 可能會覆蓋 DOM 中原本已經存在、而且更好的文字。
目標不是加入更多 ARIA。目標是讓每個介面元素的名稱、角色、狀態與用途都清楚。
用白話理解無障礙名稱
多數互動元素都有無障礙名稱。螢幕閱讀器會使用這個名稱來宣告該元素是什麼。
例如:
<button>Save changes</button>
螢幕閱讀器可能會宣告類似:「Save changes, button。」角色來自原生的 button 元素。名稱則來自其中的文字。
這是理想情況:可見文字與無障礙名稱一致。
當可見介面沒有提供完整名稱,或名稱必須來自另一個元素時,ARIA 標籤屬性就會派上用場。主要屬性包括:
aria-label:直接在元素上提供一段字串。aria-labelledby:指向一個或多個元素,這些元素的文字會成為名稱。aria-describedby:指向輔助說明文字,而不是主要名稱。
這三者彼此相關,但不能互換。
第一條規則:優先使用原生 HTML 與可見標籤
如果可以在控制項上放置可見文字,請先這麼做。
這樣比較好:
<button>Delete invoice</button>
而不是這樣:
<button aria-label="Delete invoice">
<svg aria-hidden="true" focusable="false">...</svg>
</button>
第二種模式對純圖示按鈕而言是有效的。但如果設計能容納可見文字,可見文字能幫助所有人:螢幕閱讀器使用者、語音辨識使用者、認知負荷較高的人、快速掃視的人,以及使用翻譯工具的人。
這是無障礙工作中反覆出現的主題。原生 HTML 與可見提示能解決的問題,比隱藏的中繼資料更多。同樣的原則也適用於更廣泛的按鈕語意;如果你的團隊正在稽核 UI 控制項,我們的無障礙網頁按鈕檢查清單會是本指南的良好搭配。
什麼時候 aria-label 是正確工具
當元素需要無障礙名稱,而且沒有合適的可見文字可供參照時,使用 aria-label。
典型案例是純圖示按鈕:
<button aria-label="Search">
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<!-- icon -->
</svg>
</button>
這是合理的。可見圖示暗示搜尋,但 SVG path 本身不會提供可靠的名稱。aria-label 則補上這個名稱。
其他適合的情況包括:
- 只以「X」表示的關閉按鈕。
- 需要更具體名稱的導覽地標,例如
aria-label="Product"。 - 重複出現的控制項,而可見脈絡不是按鈕文字的一部分。
例如:
<nav aria-label="Primary">
...
</nav>
<nav aria-label="Footer">
...
</nav>
兩者都是導覽地標,但它們的標籤能幫助使用者在依地標移動時加以區分。
什麼時候 aria-label 是錯誤工具
不要只是因為測試說某個元素需要標籤,就加入 aria-label。請先修正標記。
不佳:
<div role="button" tabindex="0" aria-label="Submit">Submit</div>
較好:
<button>Submit</button>
第一個例子製造了不必要的工作。你現在必須重新建立鍵盤行為、停用狀態、表單行為,以及原生按鈕本來就提供的使用者預期。
也請避免用 aria-label 以改變意義的方式重新命名可見文字。
<button aria-label="Delete invoice">Remove</button>
這看似小事,但可能讓依賴語音輸入的使用者感到困惑。如果可見按鈕寫著「Remove」,但其無障礙名稱是「Delete invoice」,使用者嘗試說「click Remove」時,可能得不到預期結果。WCAG 的「label in name」要求正是為此而存在:可見文字通常應包含在無障礙名稱中。
較好的版本:
<button aria-label="Remove invoice">Remove</button>
通常更好的做法是:
<button>Remove invoice</button>
當可見文字已經存在時,優先考慮 aria-labelledby
如果標籤文字已經在頁面上,aria-labelledby 通常比 aria-label 更好。
範例:
<h2 id="billing-title">Billing address</h2>
<section aria-labelledby="billing-title">
...
</section>
該區段的無障礙名稱現在來自可見標題。你避免了重複字串,進而減少翻譯錯誤與過時標籤。
這對表單群組尤其有用:
<fieldset aria-labelledby="shipping-speed-title">
<legend id="shipping-speed-title">Shipping speed</legend>
<label>
<input type="radio" name="shipping" value="standard">
Standard
</label>
<label>
<input type="radio" name="shipping" value="express">
Express
</label>
</fieldset>
在許多情況下,原生的 legend 不需要 ARIA 就已足夠。重點是,可見標籤應該主導。ARIA 應該連接既有意義,而不是建立第二個私有版本。
使用 aria-describedby 放說明文字,而不是名稱
描述不是標籤。
看看這個欄位:
<label for="password">Password</label>
<input id="password" type="password" aria-describedby="password-help">
<p id="password-help">Use at least 12 characters.</p>
無障礙名稱是「Password」。描述是「Use at least 12 characters.」。螢幕閱讀器可能會兩者都宣告,但它們的目的不同。
不要這樣做:
<input type="password" aria-label="Use at least 12 characters">
這會用指示來命名欄位,而不是用概念本身。使用者在表單中導覽時,想先知道這個欄位是什麼,接著才是有哪些限制。
這個區別在錯誤狀態中也很重要:
<label for="email">Email</label>
<input
id="email"
type="email"
aria-invalid="true"
aria-describedby="email-error"
>
<p id="email-error">Enter an email address in the format [email protected].</p>
標籤保持穩定。錯誤訊息則成為輔助脈絡。
重複控制項需要唯一名稱
清單與卡片是 ARIA 標籤經常變得必要的地方。
不佳:
<button>Delete</button>
<button>Delete</button>
<button>Delete</button>
螢幕閱讀器使用者若按按鈕導覽,可能會聽到三次「Delete, button」,卻沒有任何脈絡。
良好:
<button aria-label="Delete report: Q4 revenue">Delete</button>
<button aria-label="Delete report: Hiring plan">Delete</button>
<button aria-label="Delete report: Vendor list">Delete</button>
這是 aria-label 的正當用法:可見文字保持精簡,而無障礙名稱包含對象。
但請謹慎使用這個模式。如果對象名稱在附近可見,aria-labelledby 可能更容易維護:
<article>
<h3 id="report-q4">Q4 revenue</h3>
<button aria-labelledby="delete-q4 report-q4" id="delete-q4">Delete</button>
</article>
無障礙名稱會變成「Delete Q4 revenue」。這避免在屬性中重複報告標題。
不要替所有東西加標籤
不是每個元素都需要 ARIA 標籤。
靜態文字通常不需要。裝飾性圖示不需要。容器也不需要,除非它們具有有意義的地標或 widget 角色。過度標籤化會讓頁面變得吵雜,也更難導覽。
對圖片而言,請使用圖片專屬的模型:有意義的圖片需要有用的 alt;裝飾性圖片需要空的 alt=""。不要用 ARIA 標籤取代良好的圖片文字。如果你的團隊混淆了這些概念,請重新閱讀務實的圖片 alt 文字指南,並把圖片替代文字與控制項名稱分開。
常見錯誤是替每個 SVG 都加上 aria-label。如果 SVG 位於按鈕內,而按鈕已經有名稱,圖示通常應該對輔助科技隱藏:
<button aria-label="Open menu">
<svg aria-hidden="true" focusable="false">...</svg>
</button>
否則,依瀏覽器與輔助科技組合不同,使用者可能會聽到重複或奇怪的宣告。
檢查計算後的名稱,而不只是程式碼
無障礙錯誤常常通過程式碼審查,因為標記看起來似乎合理。
現代瀏覽器開發者工具可以顯示計算後的 accessibility tree。在 Chrome、Edge、Firefox 與 Safari 中,檢查元素並尋找角色、名稱與描述等無障礙資訊。你要檢查三件事:
- 角色是否符合預期?
- 無障礙名稱是否清楚且具體?
- 描述是否有幫助,而且沒有取代名稱?
接著用真正的螢幕閱讀器測試幾個流程。你不需要成為全職輔助科技專家,也能抓到基本問題。在 macOS 上,VoiceOver 是內建的。在 Windows 上,NVDA 被廣泛使用且免費。在行動裝置上,視情況測試 iOS 的 VoiceOver 與 Android 的 TalkBack。
自動化工具很有用,但它們無法可靠判斷「Open」、「Read more」或「Delete」是否具有足夠脈絡。把自動化當作網,而不是法官。這類似效能稽核:報告可以指出可疑區域,但你仍需要解讀影響。我們在不驚慌地閱讀 Lighthouse 報告中建議的同樣冷靜方法,也適用於這裡。
實用審查清單
在發布 ARIA 標籤之前,請先問:
- 這是否可以改用原生 HTML?
- 是否有可見文字應該作為標籤使用?
- 如果存在可見文字,無障礙名稱是否包含它?
- 重複控制項在脫離視覺脈絡導覽時是否具有唯一性?
- 說明文字是否透過
aria-describedby連接,而不是被硬塞進標籤? - 裝飾性圖示是否已對輔助科技隱藏?
- 是否有人在瀏覽器開發者工具中檢查過計算後的無障礙名稱?
- 是否至少用真正的螢幕閱讀器走過一次關鍵流程?
這份清單能在標籤問題變成使用者問題之前,抓到大多數情況。
良好 ARIA 的安靜紀律
良好的 ARIA 工作很少是戲劇性的。它大多是克制。
使用真正的按鈕。使用真正的標籤。讓可見名稱與無障礙名稱保持一致。只有在沒有更好的可見來源時才加入 aria-label。當頁面已經包含正確文字時,使用 aria-labelledby。使用 aria-describedby 放置輔助指示與錯誤。
當我們直接使用 Web 平台時,它會免費給開發者很多能力。ARIA 是用來補足缺口的。真正的技能,是知道什麼時候確實存在缺口。