Dev Tools & Workflow

真正有幫助的 ARIA 標籤開發者指南

ARIA 標籤不是神奇的無障礙層。用得好,它們能讓控制項更容易理解;用得隨意,則會隱藏有用文字,並造成令人困惑的介面。

The Wux Webtools Team The Wux Webtools Team 7 分鐘閱讀 AI輔助,人類審核
Illustration of a developer reviewing accessible labels and UI components on a screen.
目錄
  1. ARIA 標籤是用來命名,不是用來道歉
  2. 用白話理解無障礙名稱
  3. 第一條規則:優先使用原生 HTML 與可見標籤
  4. 什麼時候 `aria-label` 是正確工具
  5. 什麼時候 `aria-label` 是錯誤工具
  6. 當可見文字已經存在時,優先考慮 `aria-labelledby`
  7. 使用 `aria-describedby` 放說明文字,而不是名稱
  8. 重複控制項需要唯一名稱
  9. 不要替所有東西加標籤
  10. 檢查計算後的名稱,而不只是程式碼
  11. 實用審查清單
  12. 良好 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 中,檢查元素並尋找角色、名稱與描述等無障礙資訊。你要檢查三件事:

  1. 角色是否符合預期?
  2. 無障礙名稱是否清楚且具體?
  3. 描述是否有幫助,而且沒有取代名稱?

接著用真正的螢幕閱讀器測試幾個流程。你不需要成為全職輔助科技專家,也能抓到基本問題。在 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 是用來補足缺口的。真正的技能,是知道什麼時候確實存在缺口。

常見問題

每個按鈕都應該有 aria-label 嗎?
不用。具有清楚可見文字的按鈕,通常已經有良好的無障礙名稱。只有在可見文字缺少或不足時,才加入 `aria-label`,例如純圖示按鈕,或需要脈絡的重複「Delete」按鈕。
aria-label 和 aria-labelledby 有什麼差別?
`aria-label` 直接在屬性中提供文字字串。`aria-labelledby` 則指向頁面其他位置既有的文字。如果合適的可見文字已經存在,`aria-labelledby` 通常更容易維護。
aria-label 可以修好被當作按鈕使用的 div 嗎?
它可以提供名稱,但不會讓該元素像真正的按鈕一樣運作。你仍然需要處理鍵盤行為、焦點、狀態與預期語意。在大多數情況下,請使用原生 `<button>`。
aria-label 應該與可見文字完全相同嗎?
它通常應該包含可見文字,尤其是互動控制項。這能支援語音辨識使用者,也符合 WCAG label-in-name 指引的意圖。
我如何知道螢幕閱讀器會宣告什麼?
先在瀏覽器開發者工具中檢查 accessibility tree 的角色、名稱與描述。接著使用真正的螢幕閱讀器測試關鍵互動,例如 VoiceOver、NVDA、TalkBack 或 JAWS。

來源與進一步閱讀

  1. WAI-ARIA Authoring Practices Guide
  2. MDN: aria-label attribute
  3. Accessible Name and Description Computation 1.2
  4. WCAG 2.2 Success Criterion 2.5.3: Label in Name
關於作者
The Wux Webtools Team

最後更新:

繼續閱讀