Day 02 · W1 · 無障礙線 · 難度 ★★☆☆☆
本系列由 AI 協作撰寫。 內容、技術判斷、程式碼由 light-design 數位顧問團隊與 Claude 共同產出,最終由作者驗證後 publish。完整協作模式與把關方式見 Day 01。
2026 年 4 月 30 日,我們把自家網站送去申請 MODA 無障礙 AAA 標章。
送件之前,我們用自己寫的檢測工具掃過一遍。0 個 fail。
12 天後,審查結果回來了:9 條。
今天要講的不是「審查很嚴」。是一件對所有做自動化檢測的人都成立的事:
工具「有這條規則」,跟工具「抓得到這個問題」,是兩件不同的事。
那 9 條裡面,只有 2 條是我們根本沒寫規則。另外 7 條,規則檔就躺在專案裡,跑過,然後給了綠燈。
先講這個迴圈,因為它決定了所有事。

第一輪的迴圈。深色是你在動的時間,淺色是你在等的時間。等的那 12 天,你連要改什麼都不知道。
送出去到知道結果,12 天。
這 12 天你什麼都不能做,因為你不知道要改什麼。
對接案的人來說,這個數字很痛。標案合約寫「需通過無障礙標章」
你排時程時得把這段等待算進去,而且不只一輪。改完再送,又要等。
真正的問題不是等待本身,是你沒辦法在送出去之前先知道答案。
官方檢測工具是桌面 GUI 程式,你沒辦法把它接進 CI,讓每次 commit 都跑一遍。你只能寫完、送出、等、收到、改、再送。
這就是我們當初決定自己蓋一把 CLI 的原因。跑得起來的東西才能進 pipeline,進得了 pipeline 才能在寫的當下就知道。
收到報告那天,我本來以為會看到一堆沒實作的檢核項目。實際比對之後才發現不是。
當時的版本是 v0.3.4。九條意見對應的檢核碼,我一條一條回去翻專案:
| 情況 | 條數 |
|---|---|
| 規則檔不存在,根本沒檢 | 2 |
| 規則檔存在,跑過,回報通過 | 7 |
7:2。問題的大宗不是「還沒做」,是「做了但沒抓到」。
這比缺規則麻煩得多。缺規則你知道自己缺,補上就好。規則存在卻給綠燈,你會相信那個綠燈。

九條意見的根因分佈。灰色那兩格是「沒寫規則」,其餘七格都是「寫了規則但漏抓」,而且漏抓的理由各不相同。
三條意見指向同一個結構性問題。
審查意見裡有這樣的描述:展開右上角漢堡選單之後,下一個焦點要直接進入選單內容;在選單收合之前,焦點不能跑出去。另一條講聯絡頁的彈出視窗,同樣的要求。
我們的鍵盤檢測是這樣寫的:載入頁面,從頭 Tab 到尾,記錄每一站的焦點位置與樣式。
看起來合理。問題是它只走了一種狀態 —— 頁面剛打開、什麼都沒點的那個狀態。
漢堡選單展開後的焦點順序、彈出視窗開啟後的焦點是否被限制在視窗內,這些都要先做一個互動動作才會出現。工具從來沒點過任何東西,自然永遠看不到。
這不是我們特別粗心。焦點限制(focus trap)是自動化無障礙工具普遍的弱項,主流工具多數也不直接驗證這件事。原因很單純:要驗它,工具就得會操作網頁,而不只是讀網頁。
差別有多大?「讀網頁」是拿到 HTML 之後分析結構,快、便宜、可以一次跑幾百頁。「操作網頁」是開一個真的瀏覽器、找到那顆漢堡按鈕、點下去、等動畫跑完、再開始 Tab,然後判斷焦點有沒有跑出選單外。後者慢一個數量級,而且每一種元件的開啟方式都不一樣。
我們後來補的做法是:讓工具先去找頁面上「看起來會展開東西」的按鈕,逐一點開,在每個展開狀態下重跑一次焦點檢查。
聽起來理所當然。但這代表檢測工具從「靜態分析器」變成了「會操作介面的機器人」,那是完全不同量級的工程。
一條對比度意見,數字是 2.24。
標準要求 4.5:1。2.24 差得不是一點點。但我們的對比度檢測明明跑過,而且是用 Playwright 真的開瀏覽器量算出來的顏色,不是讀原始碼裡寫的色碼。
問題在於:Playwright 預設用淺色模式開頁面。我們的網站支援深色模式,而那組文字顏色只在深色模式下才會套用。
工具量的是淺色模式的網站,審查員看的是深色模式的網站。兩邊都沒錯,看的不是同一個東西。
這件事在有設計系統的專案上特別容易發生。色票通常是一組語意變數,--text-secondary 在淺色模式解析成一個值、深色模式解析成另一個值,兩邊各自都「有經過設計」。但驗證通常只做一次,而且做在預設模式上;深色那組色票的實際對比,往往從來沒有人算過,因為它在設計稿裡看起來也還好。真正的落差要等到瀏覽器把兩層顏色疊起來、算出實際比值,才會現形。而檢測工具如果只開一種模式,它連現形的機會都不給你。
這一條之後,我們加了一個旗標讓兩種模式都跑一次再合併結果:
# 淺色與深色都掃,結果合併(需要實際渲染)
a11y-moda site https://example.com --level AAA --render --dark-mode
這條最尷尬。
意見說:首頁有三個方案,三個「查看方案」連結文字一模一樣但指向不同頁面,需要各自加上 title 讓報讀軟體區分。
我們有一條規則在管連結的 title。它檢查的是:有 title 的連結,title 內容是不是跟連結文字重複多餘。
該檢查的是:文字重複、目的不同的連結,有沒有缺 title 來區分。
同一個屬性、同一條成功準則,兩個相反的方向。規則跑得好好的,一個 fail 都沒有,因為它根本在找別的東西。
這種錯 LLM 救不了。 模型再強,你叫它判斷的題目本身就問錯了,它只會很有信心地給你一個正確答案 —— 對於錯的問題。
首頁有一個客戶評價的輪播。意見說輪播需要暫停鍵,而且暫停鍵要是進入該區塊的第一個焦點。
我們的規則怎麼找輪播?看 class 名稱裡有沒有 carousel、slider、swiper 這些常見字串。
那個輪播是網站建置平台自己生成的,class 名稱完全不在名單裡。
啟發式白名單只認得你想得到的寫法。 你列了十種常見的,就漏掉第十一種。而真實世界的網站,第十一種永遠存在。
寫到這裡要講清楚立場。
這 9 條沒有一條是審查方吹毛求疵。 每一條都是真實存在、會影響真實使用者的問題 —— 鍵盤使用者打開選單後焦點跑掉、深色模式下文字看不清楚、報讀軟體唸出三個一模一樣的「查看方案」。這些如果沒被指出來,受影響的是實際在用網站的人。
審查員做的是機器目前做不到的事:開啟選單、按下 Tab、切換深色模式、用報讀軟體實際聽一遍。 那是行為與情境的判斷,不是靜態掃描。
所以問題不在制度,在工具鏈缺了「送審前自己抓」這一段。
那 9 條後來全部修掉了,工具也跟著補了對應的檢測能力。整個過程收斂到 0,第 28 天會攤開完整紀錄。今天想留下的是這三句:
明天 Day 3,講我們怎麼把規範文件餵給 AI,讓它讀完自己生出檢測規則:讀規範、生程式、跑、失敗、修、再跑的迴圈長什麼樣。