Skip to content
Anonymous

網站無障礙設計完整指南:從 Skip Link 到 Focus States

深入了解 Web Accessibility (A11y) 最佳實踐,包含跳過導覽連結、ARIA 標籤、焦點狀態、螢幕閱讀器支援等實用技巧

#accessibility #a11y #aria #wcag #focus-states

無障礙設計(Accessibility,常縮寫為 A11y)不僅是道德責任,在許多國家更是法律要求。本文將深入探討如何讓你的網站對所有使用者都友善。

目錄

  1. 為什麼無障礙設計很重要
  2. Skip to Content 跳過導覽連結
  3. ARIA 標籤與屬性
  4. Focus States 焦點狀態
  5. 色彩對比與可讀性
  6. 語義化 HTML
  7. 測試與驗證

為什麼無障礙設計很重要

受益群體

類型說明比例
視覺障礙盲人、低視力、色盲全球約 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 跳過導覽連結

問題背景

想像一下,你是一位使用螢幕閱讀器的使用者:

  1. 進入網站
  2. 聽到 “首頁連結”
  3. 聽到 “部落格連結”
  4. 聽到 “工具連結”
  5. …(重複聽 10 個導覽連結)
  6. 終於到達主要內容

每次換頁都要重複這個過程,非常痛苦!

在頁面最開始加入一個「跳過導覽」連結:

<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]確保在最上層

如何測試

  1. 打開網頁
  2. 按下 Tab
  3. 應該看到 “Skip to content” 連結出現
  4. 按下 Enter
  5. 焦點應該跳到主要內容區域

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 對比度要求

等級一般文字大型文字
AA4.5:13:1
AAA7:14.5:1

大型文字定義:≥18pt 或 ≥14pt 粗體

檢查工具

  1. Chrome DevTools

    • 右鍵 → 檢查
    • 選擇文字元素
    • 查看 Styles 面板中的對比度資訊
  2. WebAIM Contrast Checker

  3. 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

  1. 安裝 Chrome 擴充功能:axe DevTools
  2. 打開 DevTools → axe DevTools
  3. 點擊 “Full Page Scan”

eslint-plugin-jsx-a11y

npm install eslint-plugin-jsx-a11y --save-dev

手動測試

鍵盤導覽測試

  1. 只使用鍵盤瀏覽網站
  2. Tab:移動到下一個可互動元素
  3. Shift+Tab:移動到上一個
  4. Enter:啟動連結或按鈕
  5. Space:勾選/取消勾選
  6. 方向鍵:在選項中移動
  7. 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

參考資源


結語

無障礙設計不是額外的工作,而是好的網頁設計的一部分。當你為視障使用者優化時,你同時也在為任何在陽光下使用手機的人優化。當你支援鍵盤導覽時,你也在幫助那些滑鼠壞掉的使用者。

設計無障礙的網站,就是設計更好的網站。