跳到主要內容
工程品質與資安9 分鐘閱讀

從退件到通過:網站無障礙檢測的修正紀錄

網站送無障礙檢測時經歷多次退件,最後通過 A 等級。整理替代文字、標題階層、鍵盤操作、表單標籤、跳過區塊與導盲磚的實際修正方式。

這是我做過最長的一次修正:一個 Vue 3 + Vuetify 的網站要送無障礙檢測。專案前期已經用 FreeGo 自動檢測並修正過幾輪,我接手的是人工檢測結果和後續的退件修正,中間經歷多次退件,才取得 A 等級標章。

一開始我以為無障礙就是補上 alt 和 aria-label。實際做完才發現,它考驗的是整個網站的結構,而 FreeGo 這類自動檢測工具通過,不代表人工檢測會過。這篇依問題類型整理我修了什麼。

語意和基本資訊

頁面語言

螢幕報讀軟體會依 lang 決定用什麼語言朗讀,專案預設的 en 會讓中文內容被用錯誤的方式處理:

html
<html lang="zh-Hant">

網頁標題要跟著頁面變

單頁應用切換路由時,標題不會自己改變。使用者聽不出換了頁面,所以我在路由設定標題,再統一更新:

js
{
  path: '/member-login',
  meta: { title: '會員中心 > 會員登入' },
}

router.afterEach((to) => {
  document.title = `${to.meta.title} | 網站名稱`
})

標題階層

這是退件次數最多的項目。檢測看的是文件大綱,不是字體大小。

Vuetify 的 text-h3 只是樣式,不會變成真的標題。很多畫面看起來是標題,其實是 div;也有為了字大而直接用 <h1> 的地方。修正時要把視覺和語意分開:

html
<!-- 語意由標籤決定,大小由 class 決定 -->
<h1 class="text-h5">會員中心</h1>
<h2 class="text-h3">會員登入</h2>

原則是每頁一個 h1,階層不能跳級。

另外我也移除了 <h1 role="alert"> 這種寫法。alert 會讓報讀軟體立刻打斷使用者,不適合用在一般標題上。

替代文字

替代文字不是每張圖都要寫:

  • 有資訊的圖片:描述內容。
  • 純裝飾的圖片:alt 設成空字串,報讀軟體就會跳過。
html
<!-- 之前:報讀軟體會念出沒有意義的內容 -->
<v-img alt="登入頁插圖" src="login.svg" />

<!-- 之後:裝飾圖片不打擾使用者 -->
<v-img alt="" src="login.svg" />

這點和直覺相反。不寫 alt 和 alt="" 不一樣,前者可能會念出檔名。

連結和按鈕要說清楚目的

「下載」、「<」、「>」這類文字,單獨聽完全不知道作用。按鈕需要能單獨理解的名稱:

html
<v-btn icon="mdi-chevron-left" aria-label="上一項說明" />
<a href="manual.pdf" aria-label="下載手機版操作手冊 PDF">下載</a>

表單

必填要說出來

只用紅色星號,報讀軟體不一定念得出來,所以我把「必填」寫進標籤文字:

html
<v-text-field>
  <template #label>
    <span>驗證碼(必填)</span>
  </template>
</v-text-field>

標籤要和欄位關聯

每個欄位都要有對應的 label。像驗證碼這類為了版面省略標籤的欄位,就很容易被抓出來。

日期欄位要能用鍵盤操作

Vuetify 的日期選擇器需要補上鍵盤操作和焦點管理,這部分我另外寫在《讓 Vuetify 日期選擇器支援鍵盤與螢幕報讀器》。

鍵盤使用者:跳過區塊

只用鍵盤的人,每一頁都要 Tab 過整排選單才能到內容。所以每頁最上方要有一個連結,平常隱藏,Tab 聚焦時才出現:

css
.skip-link {
  position: absolute;
  top: -100px;
}

.skip-link:focus {
  top: 0;
}
js
function skipToMain() {
  document.getElementById('main-content')?.focus()
}

主要內容要加上 tabindex="-1",才能接收程式設定的焦點:

html
<main id="main-content" tabindex="-1">...</main>

導盲磚:快速移動到區塊

導盲磚是頁面上的 ::: 標記,讓使用者用快捷鍵跳到主要區塊。常見的慣例是:

快捷鍵區塊
Alt + U上方區塊
Alt + C中間主要內容
Alt + Z下方區塊

實作上是用 accesskey:

html
<a accesskey="C" href="#C" title="中間主要內容">:::</a>

語法不難,專案也已經有部分頁面做了導盲磚,真正花時間的是把它補齊。檢測要求每個頁面都要有導盲磚,但原本的頁面不是依照這個需求設計的,版面結構也各不相同,沒辦法加一個共用元件就結束。

我只能一頁一頁調整:有的要改標題區塊的排版,有的要用定位放進既有的版面,還要留意手機版會不會擠壓到內容。同時還要讓導盲磚在每一頁的位置和樣式保持一致,使用者才不會每換一頁就要重新找。

一次就改了二十個檔案。如果一開始就把上、中、下區塊做進共用的頁面版型,這件事只要改一個地方。操作說明也要寫清楚快捷鍵,使用者才知道怎麼用。

這次學到的事

  • 無障礙是結構問題,不是最後補幾個屬性就好。越晚處理,要改的頁面越多。
  • FreeGo 這類自動工具只能抓到一部分問題,實際用鍵盤和報讀軟體走一次才準。
  • 視覺和語意要分開思考,看起來是標題,不代表它就是標題。
  • 共用元件先做對,後面就能少修很多頁。
  • 退件不是壞事。每一次的退件原因,都讓我更清楚問題在哪裡。