
better-accessibility
熱門產品介面的無障礙工程,涵蓋焦點狀態、鍵盤支援、ARIA、表單以及螢幕閱讀器。當開發或審查 UI 元件、Modal 對話框、選單、表單、自訂元件,或者使用者提到「讓這個符合無障礙」或回報鍵盤/螢幕閱讀器問題時使用。觸發詞包括:accessibility, a11y, WCAG, aria, focus ring, focus-visible, focus trap, keyboard navigation, tab order, tabindex, screen reader, sr-only, aria-live, alt text, hit area, touch target, prefers-reduced-motion, autoplay, toast duration, skip link, semantic HTML, aria-label, form errors, disabled buttons, "not keyboard accessible"。
產品介面的無障礙工程,涵蓋焦點狀態、鍵盤支援、ARIA、表單以及螢幕閱讀器。當開發或審查 UI 元件、Modal 對話框、選單、表單、自訂元件,或者使用者提到「讓這個符合無障礙」或回報鍵盤/螢幕閱讀器問題時使用。觸發詞包括:accessibility, a11y, WCAG, aria, focus ring, focus-visible, focus trap, keyboard navigation, tab order, tabindex, screen reader, sr-only, aria-live, alt text, hit area, touch target, prefers-reduced-motion, autoplay, toast duration, skip link, semantic HTML, aria-label, form errors, disabled buttons, "not keyboard accessible"。
融入工藝細節的無障礙設計
無障礙設計並非開發最後才硬塞進去符合合規的勾選檢查項,而是介面工藝的底線。只要充分善用原生平台,絕大多數功能都是免費獲得的:原生元素內建鍵盤支援、真實的標籤(label)能自動朗讀,而明顯的焦點外框也只需要一行 CSS 規則。在建立或審查 UI 程式碼時請套用這些原則,並在修復時配合專案現有的樣式系統(如 Tailwind、純 CSS 或 CSS-in-JS)。
進行審查時,請先以「僅用鍵盤」的使用者身份操作介面(每個流程都必須在完全不用滑鼠的情況下完成),接著再以螢幕閱讀器使用者的身份體驗:每個控制項是否都有宣告名稱、角色(role)與目前狀態?如果不確定,請優先選擇平台預設行為而非自訂重造,且寧可移除 ARIA 也不要誤加錯誤的 ARIA。
渲染後的色彩對比度測量與顏色修復由 better-colors Skill 處理;視覺文字大小與 iOS 輸入框縮放由 better-typography 處理;空間 RTL 佈局由 better-layout 處理。
快速參考
| 類別 | 使用時機 |
|---|---|
| 焦點與鍵盤 | 焦點外框、跳過連結、tabindex、焦點擷取(focus trap)、APG 鍵盤互動模式 |
| 語意與 ARIA | 原生元素優先、按鈕 vs 連結、地標(landmarks)、可存取名稱(accessible names)、停用狀態 |
| 表單 | 標籤(Labels)、自動完成(autocomplete)、錯誤訊息、輸入類型 |
| 螢幕閱讀器 | 視覺隱藏內容、即時區域(live regions)、Toast 快訊、替換文字(alt text)、SVG |
| 點擊區域 | 目標尺寸、擴展點擊區域、碰撞規則 |
| 動態與縮放 | prefers-reduced-motion、自動播放與定時 UI、200% 縮放、頁面重繪(reflow)、rem vs px |
核心原則
1. 原生元素優先
ARIA 的第一條鐵律:只要有原生元素可用,就不要使用 ARIA。觸發動作使用 <button>,頁面導覽使用 <a href>(必須支援 Cmd/Ctrl/中鍵點擊),絕不要寫 <div onClick>。沒有 ARIA 遠比寫錯的 ARIA 更好。
2. 清晰可見的焦點外框
請針對 :focus-visible 設定樣式,而不是裸寫 :focus,這樣鍵盤使用者能看到焦點環,而滑鼠使用者不會受到干擾。優先使用瀏覽器未經修改的預設焦點指示器。如果設計需求必須自訂焦點環,請使用專案的焦點 token 或其它明確的顏色,並針對焦點環跨越的每一個相鄰背景色驗證完整指示器的可見度;只有在通過相同檢驗後才允許使用 currentColor。外框請至少保持 2px 實線邊框或等效的可見面積。絕不要在未提供經驗證的替代方案前直接使用 outline: none,並確保在高對比模式(forced-colors mode)下保留系統色彩。
3. 完整的鍵盤支援
每一個指標(pointer)互動都需要對應的鍵盤操作路徑,並遵循 ARIA APG 模式:Escape 鍵關閉覆蓋層(overlays),方向鍵在複合元件內部移動(頁籤、選單、清單框),Tab 鍵在元件之間切換,Enter 與 Space 鍵用於觸發。僅使用 tabindex="0"(加入自然 Tab 焦點順序)與 tabindex="-1"(程式化焦點),切勿使用正值,因為正值會破壞自然的焦點順序。複合元件請使用巡迴焦點(roving tabindex):目前啟用的項目為 0,其餘皆為 -1。
4. 擷取與還原焦點
Modal 對話框應為背景內容設定 inert,開啟時將焦點移入內部,關閉時將焦點還原至觸發按鈕。同時加上 overscroll-behavior: contain 以防背景內容隨之捲動。
5. 最小點擊區域
WCAG 2.5.8 的 Level AA 標準基準為 24×24 CSS 像素目標(或滿足其規定的間距、等效控制項、行內、使用者代理或必要例外條件)。為了更輕鬆地觸發,在觸控環境中建議達到 44×44px,在桌面上且密度允許時建議達到 40×40px。若視覺元素需要保持較小尺寸,可用偽元素來擴大點擊範圍。絕不要讓擴大後的點擊區域互相重疊。
6. 為每個控制項提供標籤與類型
每個輸入框都必須搭配 <label for> 或包裹於 <label> 中;placeholder 絕不能替代標籤,且標籤與控制項應共享同一個點擊目標:核取方塊與文字之間不應有無效點擊區(dead zones)。加上具有明確意義 name 的 autocomplete 屬性,並為鍵盤設定正確的 type 與 inputmode。絕不要阻擋貼上功能;使用者需要貼上密碼與一次性驗證碼。
7. 能主動宣告的錯誤訊息
在請求發起前保持送出按鈕可用,請求發起後停用按鈕並顯示載入圖示(spinner),同時保留原始標籤文字。在送出時進行驗證:使用 aria-invalid="true" 標示出錯的欄位,將 aria-describedby 指向行內錯誤文字,並將焦點切換至第一個不合法的欄位。僅在原生控制項真正無法使用時才使用原生的 disabled 屬性。只有在刻意保留可聚焦性或可探索性時才使用 aria-disabled="true";此時需透過程式碼封鎖指標、鍵盤與表單行為,並為該狀態明確設定樣式。
8. 到處都有可存取名稱
僅有圖示的按鈕需要具備描述性的 aria-label。視覺上可見的標籤文字必須出現在可存取名稱(accessible name)中。純裝飾性元素應設定 aria-hidden="true",但絕不能加在可聚焦的元素上。
9. 切勿單純依賴顏色
狀態必須提供顏色以外的輔助提示:例如在顏色旁加上圖示、文字或下劃線。根據內容與狀態確定適用哪項 WCAG 對比度要求,然後使用 better-colors 測量渲染後的字體與背景顏色對。當對比度未達標時,回報該顏色對與未符合的要求;除非使用者要求,否則請勿自行修改專案的色彩設定。
10. 尊重 prefers-reduced-motion
將動態效果包裹在 @media (prefers-reduced-motion: no-preference) 中,使其成為主動選擇(opt-in)。在減弱動態的模式下,將滑動(slide)與縮放(scale)替換為透明度淡入淡出(opacity crossfades);完全取消視差捲動與自動播放。獨立於此偏好之外的要求:自動播放的媒體必須提供可見的暫停控制項,而包含操作或錯誤提示的 Toast 快訊應保持顯示直到使用者手動關閉。
11. 宣告動態內容
針對欄位特定的驗證使用 aria-describedby;針對與特定控制項無關且非緊急的更新(例如 Toast 或搜尋結果數量),使用溫和的即時區域(role="status");僅有在與控制項無關的緊急錯誤時才使用 role="alert"。若要穩定進行重複的溫和宣告,請在更新文字前先渲染一個穩定的空區域;動態插入的 alert 在不同螢幕閱讀器上的支援度不同,必須配合目標螢幕閱讀器進行測試。
12. 依用途提供替換文字
裝飾性圖片使用 alt="";傳達資訊的圖片應描述其涵義;功能性圖片應描述其操作動作:例如搜尋圖示按鈕應設為 alt="搜尋",而非 alt="放大鏡"。
13. 結構即導覽
使用能精確描述章節內容並形成連貫大綱的標題;建議預設使用一個頁面級別的 <h1> 並搭配正確巢狀層級的標題,而非將其視為單純的 WCAG 通過/不通過規則。暴露一個可見的主要 <main> 地標。當前方有重複的導覽或頁頭組件時,將「跳至主要內容」(Skip to content)連結設為第一個可聚焦的元素。帶有錨點的標題應設定 scroll-margin-top。
14. 支援畫面縮放與文字調整
頁面必須在 200% 縮放以及 320px 寬度重繪(reflow)下正常運作且不出現橫向捲軸。在文字容器上使用 min-height 而非固定 height;在符合專案規範的前提下優先使用 rem 斷點;切勿使用 user-scalable=no 或 maximum-scale=1。
常見錯誤
| 錯誤寫法 | 修復方式 |
|---|---|
使用 outline: none 移除焦點外框 |
改為設定 :focus-visible 的樣式;滑鼠點擊時就不會顯示焦點環 |
| 假設自訂焦點顏色在所有地方都適用 | 驗證完整指示器在每一個相鄰背景色以及高對比模式下是否均清晰可見 |
在按鈕或連結上使用 <div onClick> |
觸發動作使用 <button>,導覽連結使用 <a href> |
| 僅使用 Placeholder 作為唯一的標籤 | 加上可見的 <label for>;Placeholder 在輸入文字後會消失 |
使用正數 tabindex 來修復焦點順序 |
修復 DOM 的物理順序;只使用 0 與 -1 |
| 重複的溫和更新無法穩定被宣告 | 保持一個穩定的空狀態區域並更新其文字;針對目標螢幕閱讀器進行測試 |
一般例行 Toast 使用 assertive live region |
使用 polite;assertive 僅留給緊急錯誤 |
在可聚焦的元素上使用 aria-hidden="true" |
移除該屬性,或是讓該元素變為不可聚焦 |
| 功能性圖示的 alt 只是在描述圖片本身 | 描述其執行的動作:例如 alt="搜尋",而非 alt="放大鏡" |
使用 maximum-scale=1 防止 iOS 輸入框縮放 |
移動端輸入框字體設為 16px(參見 better-typography);絕不要禁止使用者縮放 |
| 表單合法前停用送出按鈕 | 保持送出按鈕可用;在送出時進行驗證並聚焦至第一個錯誤欄位 |
審查輸出格式
僅在使用者要求進行獨立的無障礙審查時使用此格式。當由 better-interface 統籌審查時,請向該 Skill 提供專業領域的證據與發現,並由其輸出格式、嚴重性等級、整合規則、上限與最終裁定優先適用。
獨立審查結果請分為兩個部分呈現。
發現
將所有已確認的發現按原則進行分組。使用包含 Severity、Location、Before、After 與 Why 欄位的 Markdown 表格。切勿使用獨立的 "Before:" / "After:" 換行行數。
- Severity:
HIGH會阻礙任務完成、對輔助技術隱藏內容,或造成系統性的無障礙失效;MEDIUM會顯著增加互動難度;LOW屬於局部優化細節。 - Location:引用
path/to/file:line。如果產出物沒有原始碼檔案,請改為引用明確的畫面與元件名稱。 - Before / After:展示目前的實作方式以及可直接執行的替換程式碼。
- Why:指出違反的原則及其對使用者的影響。
將重複出現的系統性問題整合為一行,並列出所有受影響的位置。無發現的原則請直接省略。
範例
到處都有可存取名稱
| Severity | Location | Before | After | Why |
|---|---|---|---|---|
| HIGH | src/Dialog.tsx:42 |
<button><XIcon /></button> |
加上 aria-label="Close";將圖示標記為 aria-hidden="true" |
僅有圖示的控制項缺乏可存取名稱 |
| HIGH | src/Nav.tsx:18 |
<a href="/settings"><GearIcon /></a> |
加上 aria-label="Settings" |
螢幕閱讀器無法讀取連結目標 |
清晰可見的焦點外框
| Severity | Location | Before | After | Why |
|---|---|---|---|---|
| HIGH | src/button.css:12 |
button:focus { outline: none; } |
button:focus-visible { outline: 2px solid; outline-offset: 2px; } |
鍵盤使用者無法看到焦點位置 |
| HIGH | src/Menu.tsx:31 |
focus:outline-none |
focus-visible:outline-2 focus-visible:outline-offset-2 |
選單導覽缺乏清晰可見的焦點指示器 |
能主動宣告的錯誤訊息
| Severity | Location | Before | After | Why |
|---|---|---|---|---|
| HIGH | src/EmailField.tsx:27 |
錯誤僅透過 border-red-500 顯示 |
加上 aria-invalid="true" + aria-describedby="email-error" 並搭配行內錯誤文字 |
僅依賴顏色既無法說明也無法宣告錯誤 |
| MEDIUM | src/SignupForm.tsx:64 |
表單合法前停用送出按鈕 | 保持送出按鈕可用;失敗時將焦點切換至第一個錯誤欄位 | 停用的操作會隱藏需要修復的內容 |
最小點擊區域
| Severity | Location | Before | After | Why |
|---|---|---|---|---|
| MEDIUM | src/Toolbar.tsx:22 |
size-4 的純圖示按鈕 |
使用 after:absolute after:size-11 將點擊區域擴展至 44×44px |
目標過小,無法進行可靠的觸控輸入 |
驗證與最終裁定
在發現部分之後:
- Verification:列出執行的具體檢查項目與觀察到的結果,適用的話包含鍵盤游標切換、可存取名稱檢驗,以及螢幕閱讀器或自動化檢查。若某項檢查未執行,請說明仍需驗證的內容。
- Verdict:`





