我們去參加鐵人賽了——30 天,把一張 AAA 標章的誕生過程全部攤開
我們參加了 2026 iThome 鐵人賽,Modern Web 組,30 天連載完賽。
題目是一件我們真的做完的事:一個不寫 Python 的前端,用 AI 蓋出一把網頁無障礙檢測 CLI,拿自家官網當白老鼠,送數位發展部審查,拿到 MODA 無障礙 AAA 標章。從第一個 commit 到標章核發,中間 26 天——工具不是先蓋好才送審的,是送件當天 repo 才剛開,被退件三次一路逼出來的。
這篇是完整目錄。30 篇加一篇附錄,每篇一句話講清楚在講什麼,讓你不用點進去才知道值不值得讀。
這 30 天在講什麼
兩條線交錯著走。
- AI 線:一個不會寫某種語言的人,怎麼靠 AI 把構想推到 PyPI、推到政府認證。包含哪些地方 AI 幫得上、哪些地方它把人坑得很慘。
- 無障礙線:Tab 鍵走不走得到那顆按鈕、焦點跑到哪裡看不看得見、手機上的 icon 按鈕手指按不按得中、螢幕縮到 320px 版面會不會爆。這些掛在「無障礙」名下,但同時就是使用者體驗的地基。
中間兩週各自純化,頭尾則交織在一起。工具本身(a11y-moda)是 MIT 授權、原始碼公開,上了 PyPI,也內建 Claude Code、Cursor、Copilot、Aider 與通用 agent 五種整合模板,一行指令就能接進你現在用的 AI 助手。任何人都可以裝起來,自己驗證我們講的每一句話。這個設計背後的取捨,我們寫過一篇:為什麼我們把無障礙工具同時上 PyPI 和包成 AI Skill。
還有一件事先說在前面:這個系列由 AI 協作撰寫,第一篇開頭就攤開了協作方式與把關流程。我們公司的業務本質就是教企業怎麼這樣用 AI,所以這 30 天本身就是一份 case study。
連載目錄
下面依發布順序排,連結會另開新視窗到 iThome 原文。
W1為什麼要蓋這把刀7 篇
開場先給結果:一行指令跑完自家 8 頁 AAA 全站掃描。重點是那句「C 是選擇題,E 是申論題」——AAA 自評 20 題全部都是 E 碼,這就是整個系列要解的問題。
送件前自己掃 0 fail,12 天後審查意見回了 9 條。其中 7 條的規則檔早就躺在專案裡、跑過、還給了綠燈——拆解自動化檢測的四種典型盲區。
貼出真的 git log:5 小時 5 分、8 個 commit,自評覆蓋率 12/20 跑到 20/20。拆解「讀規範 → 生規則 → 自驗」三段齒輪,以及一個檔一條規則的代價——import 路徑寫錯會靜默消失,不報錯。
- Day 0420 秒裝好,然後它抓到自己(另開新視窗)
一台 Windows 11 全新虛擬環境全程計時:20 秒從空環境到第一個 issue,不裝瀏覽器、不要 API key。146 條規則有 50 條不用瀏覽器;第一個抓到的問題,出在工具自己的說明文字。
四個工具對同一個壞頁攤開比:計數單位不同,數字不能直接比;「0 個問題」可能只是引擎版本的資訊。在台灣送件,你對的是碼表,不是條文。
規範從 110.07 換到 115.11,第一次算出要補 109 條;逐條讀完只有 7 條是換版新增,其餘 102 條是本來就欠的債。換版的成本是「新增的」,不是「還沒做的」。
工具裡六個閾值全是某天某個人畫的線:標籤最長 16 字、三顆以上才算頁籤群組。檢測工具的閾值是立場不是事實,而那些判斷沒寫在程式碼以外的任何地方——所以開源。
W2AI agent 怎麼生規則7 篇
這個專案的 Python 沒有一行是作者打出來的。翻 git 想量 AI 寫了多少:78 個 commit 有 42 個標了 AI,量不出來。人做的四件事:架構、取捨、紅線、驗收。
50 條規則各寫了兩個版本:scan 看瀏覽器裡活的 DOM,lint 讀 JSX 語法樹,碼號相同、邏輯完全不同。語法樹版貴一倍(1,949 行 vs 3,815 行),「這個檔案看不出來」是常態。
對比度公式十行就寫得完,難的是決定「哪一個顏色算背景」。漸層上的白字在 76% 的位置穿過 4.5:1,同一行字前四分之三合格;量不到的時候不要給數字。
- Day 11我的工具把整個部落格當成訊息日誌(另開新視窗)
一條找「訊息日誌」的規則在自家站 43 頁裡 32 頁報問題,因為 log 命中了 BlogList。偽陽性比漏抓致命:漏抓少報一條,偽陽性讓人學會無視整個工具。兩次修正,fail 一條沒少。
交給 AI 判的規則,被檢查的網頁文字會進 prompt、畫面會進截圖:網頁可以叫工具說它通過。讀模型回答只認行首前綴,「盡量救回來」在輸入不可信時是漏洞不是好習慣。
沒寫過 outline: none,每個停留點都畫了 2px 外框,鍵盤按過去 33 個停留點仍有兩個看不見。焦點外框畫在元件外面,要跟旁邊的顏色比;25% 透明的藍合成後只剩 1.54:1。
工具有一份「不准按」清單:付款、結帳、刪除……但空表單的送出鍵不在上面。aria-required 不會啟動瀏覽器驗證、novalidate 會關掉它,兩者都讓探針的空送變成真送。
W3網頁無障礙的真功夫7 篇
- Day 15我幫大部分的圖決定了它不用被唸出來(另開新視窗)
把自家六頁 155 張圖全撈出來數,大部分的 alt="" 是作者的決定。alt="" 跟沒有 alt 是相反的兩件事;判準不是圖多重要,是拿掉之後這個地方還講不講得清楚。
自家站沒有一個「了解更多」,四項檢查 0 缺失,換個抽字串的算法卻掉出 59 條差異。aria-label 會蓋掉可見文字,只讀 textContent 看不到那一層。工具的價值是把判斷寫成一句可以被否證的話。
同一個站切成深色再量一次:焦點外框不合格從 7/174 變成 173/174,CSS 一行沒改。深色模式不是反色,是同一份 CSS 的另一個分支,:focus 這種狀態樣式最容易被漏掉。
部落格四個分類頁籤,Tab 只停一站、另外三顆按不到,而這是對的:頁籤群組由方向鍵接手。移出 Tab 序列要有別的鍵接手;roving 是宣告加行為兩半,只做前半比不做更糟。
空表單送出,焦點準確跳到第一個沒填的欄位,那一行作者沒寫過。required 免費送焦點跳轉,但碼表要的是文字描述「並」跳轉,原生提示不進 DOM。五種寫法量下來只有一種同時成立。
- Day 20CLI 能跑,不等於 AI 會用對(另開新視窗)
隨 package 出貨的 agent 說明書,真正在做事的不是「怎麼用」,是六條「不准」:不准憑印象回答、caveat 不准自動修、缺套件不准替人裝。而那份要 AI 別憑印象的檔案,自己寫著一個過期的數字。
碼表 244 條有 216 條標「需人工判斷」,一半用純程式做掉,真的叫模型的 44 條。首頁 51 次判定只報 1 次問題;刪掉快取重判 51 次,51 筆回覆逐字相同。LLM 補的不是聰明,是可重複。
W4真的有用嗎9 篇
5 月整站 30 頁 0 fail、標章核發;9 月同一個站 33 fail。出 fail 的四個樣式檔最後修改全在核發前,四條檢測碼 110.07 沒有、115.11 才有,對應準則全是 WCAG 2.2 新增。自評表問的是 110.07 的題,變的是尺。
昨天那 33 個 fail,站上當天改了 27 個檔。出貨給 agent 的不是修法,是一份協定:修之前掃一次、修之後掃一次,用 (rule_id, snippet, status) 三元組比成 fixed / still / new 三桶。結果 fixed 36、new 0——動了 27 個檔沒弄壞任何東西,這句話是 diff 說的。
320px 不是哪支手機的寬度,是 1280 放大 400% 的規範門檻。自家站 30 頁零頁橫捲,所以把六個常見兇手各做成一頁放回去掃:五個中,表格要欄位多到換不了行才會。工具只說哪一頁捲了,是誰撐開的得回瀏覽器自己找。
同一句登入表單需求,乾淨的 Claude 子代理各寫三份:一組不查、一組先查表單規則再寫。lint 幾乎平手,查表改變的只有它查到的那幾條(fieldset、格式說明),兩邊都缺的五項全不在表上;照表寫還多了一種新錯。查的範圍決定改善的範圍,代價是多 29% token。
五件從 git 紀錄挖出來、AI 沒做而我以為它會自己做的事:旗標沒接到每一層、條文被翻小、跳頁連結只認一種長相、寫死的數字沒人更新、第三方的 fail 算在站頭上。沒有一件是 AI 寫錯了我說的話,它做了我說的,我以為我說了更多。每一件後來都變成一句寫給 AI 的規矩。
開源不是把程式碼放上去那一下,每次發版都要走同一份九步清單。第三步「README 必改」是漏過的那一步,連漏五個版本,PyPI 頁面停在舊指令,直到用戶第一次打開套件頁才發現。今天用這份清單走完第 20 個版本,0.6.0 正式上 PyPI。
4 月 30 日送件,5 月 12、21、25 日三次審查意見,5 月 26 日核發 AAA 標章,26 天。三輪意見,工具都在收到當天先動,網站接著改,改站時間逐輪變短:8 天、1 天、當天。但不是每一條都補得上,焦點可見那條規則太寬鬆的問題,直到最新版本才量化,這是唯一一個例外,寫出來比省略掉誠實。
40 筆 caveat 裡,兩筆白色圖示補上實際紫底後,對比為 3.64:1,符合本次檢查門檻;工具重跑仍留下提醒。原始報告保留,覆核結論另外記,其餘 38 筆照實列出未完事項。案例可以收尾,網站的所有檢查不能因此被寫成完成。
回到第一天答應的案例、開源 CLI、系列文章與工作手冊,逐項交代入口。留下先寫驗收條件再請 AI 實作的方法,以及作者親筆補上的三十天協作心得。
附錄用 AI 做出一個你自己領域的工具1 篇
把散在各篇的做法收成一份可照填的手冊:先選一個能驗收的小問題,填規則卡標來源與操作定義,準備已知符合、已知不符合、邊界條件、證據不足四種測例,再交給 AI 實作與驗收。附完整規則卡與測例模板,是 Day 01 承諾的第四樣東西。
30 天全部發完了。原文都在 iThome,也可以從 iThome 上的系列目錄(另開新視窗) 一次看完。
四週怎麼走的
四週的骨架,加上最後的附錄。
- W1Day 1—7為什麼要蓋這把刀
- 痛點、規範長什麼樣、現有工具的邊界在哪。
- W2Day 8—14AI agent 怎麼生規則
- 技術核心:prompt 工程、AI 友善的架構設計、LLM 與 VLM 怎麼判斷,還有安全防線。
- W3Day 15—21網頁無障礙的真功夫
- AI 比例下降,Playwright 上場。每天拆一個前端常見的誤解。
- W4Day 22—30真的有用嗎
- 拿真實網站跑、AI 協作的翻車實錄、標章送審到核發的三輪完整紀錄,最後逐項對帳。
- 附錄系列附錄用 AI 做出一個你自己領域的工具
- 把散在各篇的做法收成一份可照填的手冊:規則卡、四種測例、驗收交付。
跟很多 30 天系列不一樣的地方:每一篇都有可以複製貼上執行的程式碼,跟可以驗證的結果。白老鼠是我們自家網站——從第一天掃出來的兩個 fail,到第 22 天換版後冒出的 33 個 fail,修壞的部分全部公開。
為什麼把目錄放在自己網站
因為 iThome 是別人的地。
賽事期間流量會集中在那邊,這是好事。但 30 天結束之後,這個系列是不是還找得到、還排不排得上搜尋、能不能被我們自己的客戶讀到,那要看它有沒有一份長在自家網站上的入口。
內容放在平台上是租的,放在自己的網域才是資產。這是我們對客戶講了很多次的話,自己當然也得照做。
你可以怎麼用這 30 天
看你是誰,路線不一樣。
- 正在被無障礙審查退件的人:直接跳 Day 2。那篇講的是我們送件前自己掃 0 fail、12 天後審查回了 9 條意見,以及那 9 條為什麼工具沒抓到。官方工具抓不到的那一塊,我們之前也寫過:Freego 全綠也可能退件。
- 想知道 AI 到底能幫到哪的老闆:W2 那週是核心。重點不是「AI 好厲害」,是選對機制比選對模型重要——20 題自評裡,11 題用最樸素的 DOM 解析就夠了,丟給 LLM 是浪費錢又不穩定。
- 前端工程師:W3 每天拆一個常見誤解,Playwright 上場,全部有程式碼。
- 想看真實數據的人:W4 是實測週,包含 AI 協作的翻車實錄跟標章送審到核發的完整紀錄。我們也自爆過一次:把自己的無障礙報告攤給你看。
工具是副產品,方法才是產品
合理的疑問:顧問公司不是應該去接案嗎,做工具幹嘛?
因為工具能被外部驗證,形容詞不行。講一百次「我們懂無障礙」,不如把程式碼開源出來讓人看,再加上一張官方核發的標章。
而真正在賣的東西也不是那把工具——是「一間不寫 Python 的公司,怎麼用 AI 把一個構想推到能被政府驗收」這套流程。這個流程可以搬到你公司的任何領域。
如果你公司正在被無障礙審查卡住,或者想知道現有的工具流程接不接得上 AI——寫信給我們,先問問題不收費。想看服務怎麼收費,方案頁都寫在上面了。










