• Anonymous
網站無障礙設計完整指南:從 Skip Link 到 Focus States
深入了解 Web Accessibility (A11y) 最佳實踐,包含跳過導覽連結、ARIA 標籤、焦點狀態、螢幕閱讀器支援等實用技巧
#accessibility
#a11y
#aria
#wcag
#focus-states
無障礙設計(Accessibility,常縮寫為 A11y)不僅是道德責任,在許多國家更是法律要求。本文將深入探討如何讓你的網站對所有使用者都友善。
目錄
為什麼無障礙設計很重要
受益群體
| 類型 | 說明 | 比例 |
|---|---|---|
| 視覺障礙 | 盲人、低視力、色盲 | 全球約 2.85 億人 |
| 聽覺障礙 | 聾人、重聽 | 全球約 4.66 億人 |
| 運動障礙 | 無法使用滑鼠、手部震顫 | 因人而異 |
| 認知障礙 | 閱讀困難、注意力缺陷 | 因人而異 |
| 臨時障礙 | 手臂受傷、強光環境 | 每個人都可能遇到 |
法律要求
- 🇺🇸 美國:ADA(Americans with Disabilities Act)
- 🇪🇺 歐盟:European Accessibility Act
- 🇹🇼 台灣:身心障礙者權益保障法
- 🌐 國際標準:WCAG 2.1(Web Content Accessibility Guidelines)
WCAG 合規等級
| 等級 | 說明 | 要求 |
|---|---|---|
| A | 最低要求 | 網站基本可用 |
| AA | 建議標準 | 大多數法規要求此等級 |
| AAA | 最高標準 | 對特定內容的額外增強 |
Skip to Content 跳過導覽連結
問題背景
想像一下,你是一位使用螢幕閱讀器的使用者:
- 進入網站
- 聽到 “首頁連結”
- 聽到 “部落格連結”
- 聽到 “工具連結”
- …(重複聽 10 個導覽連結)
- 終於到達主要內容
每次換頁都要重複這個過程,非常痛苦!
解決方案:Skip Link
在頁面最開始加入一個「跳過導覽」連結:
<body>
<!-- Skip Link:視覺上隱藏,但螢幕閱讀器和鍵盤可用 -->
<a href="#main-content" class="skip-link">
Skip to content
</a>
<header>
<!-- 導覽列 -->
</header>
<main id="main-content">
<!-- 主要內容 -->
</main>
</body>
CSS 實作
.skip-link {
/* 預設:視覺上隱藏 */
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.skip-link:focus {
/* 獲得焦點時:顯示出來 */
position: fixed;
top: 1rem;
left: 1rem;
z-index: 100;
width: auto;
height: auto;
padding: 0.5rem 1rem;
margin: 0;
overflow: visible;
clip: auto;
white-space: normal;
/* 樣式 */
background-color: #00ff88;
color: #0a0a0f;
font-weight: 600;
border-radius: 0.5rem;
text-decoration: none;
}
Tailwind CSS 版本
<a
href="#main-content"
class="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z-[100] focus:px-4 focus:py-2 focus:bg-hacker-green focus:text-hacker-bg focus:rounded-lg focus:font-semibold"
>
Skip to content
</a>
類別說明
| 類別 | 作用 |
|---|---|
sr-only | 螢幕閱讀器專用(視覺隱藏) |
focus:not-sr-only | 獲得焦點時取消隱藏 |
focus:absolute | 獲得焦點時絕對定位 |
focus:top-4 focus:left-4 | 定位在左上角 |
focus:z-[100] | 確保在最上層 |
如何測試
- 打開網頁
- 按下 Tab 鍵
- 應該看到 “Skip to content” 連結出現
- 按下 Enter
- 焦點應該跳到主要內容區域
ARIA 標籤與屬性
什麼是 ARIA
ARIA(Accessible Rich Internet Applications)是一組 HTML 屬性,用於增強網頁的無障礙性。
常用 ARIA 屬性
aria-label
為沒有可見文字的元素提供標籤:
<!-- ❌ 沒有說明的按鈕 -->
<button>
<svg>...</svg>
</button>
<!-- ✅ 有 aria-label -->
<button aria-label="Open menu">
<svg aria-hidden="true">...</svg>
</button>
aria-hidden
從無障礙樹中隱藏純裝飾元素:
<!-- 裝飾性 emoji,不需要讀出來 -->
<span aria-hidden="true">🚀</span>
<!-- 有意義的內容,需要讀出來 -->
<span>Launchpad</span>
aria-expanded
表示可折疊元素的狀態:
<button
aria-expanded="false"
aria-controls="mobile-menu"
>
Menu
</button>
<div id="mobile-menu" hidden>
<!-- 選單內容 -->
</div>
在 JavaScript 中更新:
function toggleMenu() {
const isOpen = menu.hidden;
menu.hidden = !isOpen;
button.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
}
aria-current
表示當前頁面或選中項目:
<nav>
<a href="/" aria-current="page">首頁</a>
<a href="/blog">部落格</a>
<a href="/tools">工具</a>
</nav>
重要原則:不要過度使用 ARIA
“No ARIA is better than bad ARIA” — W3C WAI
優先使用語義化 HTML:
<!-- ❌ 使用 ARIA 模擬按鈕 -->
<div role="button" tabindex="0" onclick="...">
Click me
</div>
<!-- ✅ 使用原生 button -->
<button onclick="...">
Click me
</button>
Focus States 焦點狀態
為什麼焦點狀態重要
鍵盤使用者需要知道當前焦點在哪裡。沒有明顯的焦點指示器,他們就會「迷路」。
預設焦點樣式
瀏覽器預設會顯示焦點外框,但許多開發者會移除它:
/* ❌ 千萬不要這樣做! */
*:focus {
outline: none;
}
正確做法:優化而非移除
/* ✅ 移除預設樣式,但加上更好的替代 */
button:focus {
outline: none;
box-shadow: 0 0 0 2px #0a0a0f, 0 0 0 4px #00ff88;
}
focus-visible 選擇器
只對鍵盤焦點顯示樣式,滑鼠點擊時不顯示:
/* 只在鍵盤導覽時顯示焦點環 */
button:focus-visible {
outline: 2px solid #00ff88;
outline-offset: 2px;
}
/* 滑鼠點擊時隱藏 */
button:focus:not(:focus-visible) {
outline: none;
}
Tailwind CSS 焦點樣式
<!-- 基本焦點環 -->
<button class="focus:outline-none focus:ring-2 focus:ring-hacker-green">
Click me
</button>
<!-- focus-visible 版本 -->
<button class="focus:outline-none focus-visible:ring-2 focus-visible:ring-hacker-green">
Click me
</button>
建立可重用的焦點工具類別
在 global.css 中:
.focus-ring {
@apply focus:outline-none
focus-visible:ring-2
focus-visible:ring-hacker-green
focus-visible:ring-offset-2
focus-visible:ring-offset-hacker-bg;
}
使用:
<button class="focus-ring">Click me</button>
<a href="/blog" class="focus-ring">Blog</a>
<input type="text" class="focus-ring" />
色彩對比與可讀性
WCAG 對比度要求
| 等級 | 一般文字 | 大型文字 |
|---|---|---|
| AA | 4.5:1 | 3:1 |
| AAA | 7:1 | 4.5:1 |
大型文字定義:≥18pt 或 ≥14pt 粗體
檢查工具
-
Chrome DevTools:
- 右鍵 → 檢查
- 選擇文字元素
- 查看 Styles 面板中的對比度資訊
-
WebAIM Contrast Checker:
-
Lighthouse:
- DevTools → Lighthouse → Accessibility
常見問題與修復
問題:淺灰色文字
/* ❌ 對比度不足 (約 2.5:1) */
.text-gray-400 { color: #9ca3af; }
/* ✅ 提高對比度 (約 4.6:1) */
.text-gray-500 { color: #6b7280; }
問題:綠色連結在深色背景
/* 確保 #00ff88 在 #0a0a0f 上有足夠對比度 */
/* 這個組合對比度約 12.8:1,非常好! */
不要只依賴顏色傳達資訊
<!-- ❌ 只用顏色表示狀態 -->
<span class="text-red-500">Error</span>
<span class="text-green-500">Success</span>
<!-- ✅ 顏色 + 圖示 -->
<span class="text-red-500">
<svg aria-hidden="true">✗</svg>
Error
</span>
<span class="text-green-500">
<svg aria-hidden="true">✓</svg>
Success
</span>
語義化 HTML
為什麼語義化很重要
螢幕閱讀器依賴 HTML 結構來理解內容:
<!-- ❌ 完全沒有語義 -->
<div class="header">
<div class="nav">
<div class="link">Home</div>
</div>
</div>
<div class="content">...</div>
<div class="footer">...</div>
<!-- ✅ 語義化 HTML -->
<header>
<nav>
<a href="/">Home</a>
</nav>
</header>
<main>...</main>
<footer>...</footer>
常用語義化元素
| 元素 | 用途 |
|---|---|
<header> | 頁首或區塊標頭 |
<nav> | 導覽區域 |
<main> | 主要內容(每頁只應有一個) |
<article> | 獨立的內容區塊 |
<section> | 主題內容分段 |
<aside> | 側邊欄或補充內容 |
<footer> | 頁尾或區塊尾 |
<figure> | 圖片或圖表 |
<figcaption> | 圖片說明 |
標題層級
<!-- ✅ 正確的標題層級 -->
<h1>網站標題</h1>
<h2>第一章</h2>
<h3>1.1 小節</h3>
<h3>1.2 小節</h3>
<h2>第二章</h2>
<h3>2.1 小節</h3>
<!-- ❌ 跳過層級 -->
<h1>網站標題</h1>
<h4>錯誤:跳過 h2 和 h3</h4>
表單無障礙
<!-- ✅ 正確的表單標籤 -->
<form>
<label for="email">Email</label>
<input type="email" id="email" name="email" required />
<label for="password">Password</label>
<input type="password" id="password" name="password" required />
<button type="submit">Login</button>
</form>
<!-- ❌ 沒有關聯的標籤 -->
<form>
<span>Email</span>
<input type="email" />
<div>
<input type="submit" value="Submit" />
</div>
</form>
測試與驗證
自動化工具
Lighthouse
# Chrome DevTools → Lighthouse → Accessibility
# 或使用 CLI
npx lighthouse https://your-site.com --only-categories=accessibility
axe DevTools
- 安裝 Chrome 擴充功能:axe DevTools
- 打開 DevTools → axe DevTools
- 點擊 “Full Page Scan”
eslint-plugin-jsx-a11y
npm install eslint-plugin-jsx-a11y --save-dev
手動測試
鍵盤導覽測試
- 只使用鍵盤瀏覽網站
- Tab:移動到下一個可互動元素
- Shift+Tab:移動到上一個
- Enter:啟動連結或按鈕
- Space:勾選/取消勾選
- 方向鍵:在選項中移動
- Escape:關閉對話框
檢查清單
- 可以用鍵盤到達所有互動元素
- 焦點順序合理(從上到下,從左到右)
- 焦點指示器清晰可見
- 沒有鍵盤陷阱
- Skip Link 可用
螢幕閱讀器測試
- macOS:VoiceOver(Command + F5)
- Windows:NVDA(免費)或 JAWS
- iOS:VoiceOver(設定 → 輔助使用)
- Android:TalkBack
常見問題檢查
| 問題 | 如何檢查 |
|---|---|
| 圖片缺少 alt | 檢查所有 <img> 是否有 alt 屬性 |
| 表單缺少 label | 每個 input 是否有關聯的 label |
| 對比度不足 | 使用對比度檢查工具 |
| 焦點不可見 | 用鍵盤瀏覽,確認可以看到焦點 |
| 標題層級跳躍 | 使用 HeadingsMap 擴充功能 |
總結
無障礙設計核心原則(POUR)
| 原則 | 英文 | 說明 |
|---|---|---|
| 可感知 | Perceivable | 使用者必須能感知資訊 |
| 可操作 | Operable | 使用者必須能操作介面 |
| 可理解 | Understandable | 資訊和操作必須可理解 |
| 健壯性 | Robust | 內容必須能被各種技術解讀 |
快速檢查清單
- 加入 Skip to Content 連結
- 所有圖示按鈕有 aria-label
- 裝飾性元素有 aria-hidden=“true”
- 可折疊元素有 aria-expanded
- 所有互動元素有可見焦點狀態
- 色彩對比度符合 AA 標準
- 使用語義化 HTML
- 標題層級正確
- 表單有正確的 label
參考資源
結語
無障礙設計不是額外的工作,而是好的網頁設計的一部分。當你為視障使用者優化時,你同時也在為任何在陽光下使用手機的人優化。當你支援鍵盤導覽時,你也在幫助那些滑鼠壞掉的使用者。
設計無障礙的網站,就是設計更好的網站。