iT邦幫忙

2026 iThome 鐵人賽

DAY 7
0
Modern Web

前端不寫 Python,照樣 ship 一把網頁無障礙 CLI系列 第 7

Day 07:六個魔術數字都是我拍板的,所以我把程式碼送出去

  • 分享至 

  • xImage
  •  

Day 07 · W1 · AI 線 · 難度 ★★☆☆☆

本系列由 AI 協作撰寫。 內容、技術判斷、程式碼由 light-design 數位顧問團隊與 Claude 共同產出,最終由作者驗證後 publish。完整協作模式與把關方式見 Day 01

Day 4 那個 _MAX_LABEL_LEN = 16 我說留到今天講。

今天不是要再講一次那個漏抓。是要講那個數字是誰決定的

答案是我。而且不只那一個。

if b_count >= 5 and sem_count == 0:

一句話主軸:開源不是慷慨。是因為那些判斷除了程式碼以外,我沒有寫在任何地方。

六個數字,六次拍板

隨手從規則檔裡抽出來的:

rule_id 程式碼原文 那個數字在決定什麼
HM1130105E b_count >= 5 and sem_count == 0 幾個 <b> 才算濫用非語意標記
AR2410302E len(children) >= 5 幾個子元素才算一個「訊息日誌」容器
FA2410303E len(text) > 80 超過幾個字就不當作狀態訊息
GN2320400E len(existing) > 3 and len(text) > 3 多短的連結文字不列入比對
GN1240301E len(out_of_viewport) > len(tab_stops) / 2 多少比例的焦點在視窗外算異常
GN1330100E 5 < len(text) < 300 什麼長度的文字算「錯誤訊息」

沒有任何一條規範文字叫我們寫這些數字。

規範說的是「不應濫用非語意標記」。5 是我們替那句話決定的操作定義。某天下午,看了幾個網站,覺得這個數字差不多。

四個 <b> 的網站不會被判,六個會。那條線在哪,是一個人畫的。

這件事本身不可避免。規範用文字寫,程式要能執行,中間一定得有人把「濫用」翻譯成一個可以比大小的數字。問題不在有沒有這條線,在這條線對不對得上你的網站,以及你看不看得見它

六個硬編閾值的對照圖:左欄列出六條規則的程式碼原文,包含五個 b 標籤、五個子元素、八十字、三字、二分之一、以及五到三百字這些門檻;右欄對應寫出規範實際說的話,例如「不應濫用非語意標記」,顯示規範只給方向、數字全部由實作者決定

左邊是程式碼,右邊是規範原文。中間那段落差,就是我拍板的地方。

不只是數字,還有「DOM 長什麼樣」

閾值只是其中一種拍板。規則對頁面結構也做了假設,而每個網站的結構不一樣。

三個實例:

rule_id 程式碼裡的假設 誰會被誤判
GN1240102E 主要內容錨點接受 <main>role="main"id="main""content""maincontent" 掛在 #app#root 的 SPA
GN1240100E 只看 <body> 裡前 8<a> 找 skip link 頁首有長工具列的站
GN1240500E 導覽認 <nav>role="navigation" 用其他語意結構做導覽的站

第一條特別值得看。一個 React 專案掛在 <div id="root">,內容區塊語意上完全正確,但因為 id 不叫 main 也不叫 content,我們會報它缺少內容錨點。

那不是它的錯,是我當初只想到三個名字。

這一類假設比數字更難察覺。閾值至少是個數字,看到就知道是人挑的;結構假設藏在條件式裡,長得像事實。id="main" 讀起來像標準,其實只是常見寫法之一。

第二條的 [:8] 同時是數字也是結構假設,等於第七個魔術數字。

還有更土的。那條找訊息日誌的規則,是靠 class 名稱猜的:含 logchatmessage-listnotifications 就當候選。然後就踩到了:log 這個字串會中 blogdialoglogologincatalog。所以程式碼裡多了一條排除清單,專門把這些洗掉。

那條排除清單旁邊還附了一句註解說明為什麼。它是一個猜測的補丁,不是規範裡的東西。

現在你只有兩條路

想調那個 5,你能做什麼?

規則設定檔      不存在(grep toml / config_file / rcfile 全空)
CLI 能調的      --ignore(整條關掉)· --freego-only · --strict-third-party
閾值狀態        全部寫死在規則檔裡
  1. --ignore HM1130105E —— 整條關掉,連帶失去這條規則所有價值
  2. 改原始碼 —— 這需要原始碼在你手上

第一條是把嬰兒跟洗澡水一起倒掉。一個網站合理地用了很多 <b>,不代表它不想檢查語意標記,只代表那個 5 對它不對。

但開源不等於好調

寫到這裡我本來想收尾了:「所以你看,開源讓你能改。」

然後我去查了 axe-core 怎麼做的。

axe.configure           runtime function
checks[].options        官方明文可傳參數給個別檢查
rules[].enabled         可單條開關
自訂規則 / 覆寫既有規則   都支援

用 axe 的人不需要 fork。想把某個門檻調鬆,寫一段設定就好,原始碼一個字都不用動。pa11y 有設定檔、Lighthouse 有 custom config,都是同一套路。

這不是小事。一旦要 fork,你就得自己維護那份分支:上游改了規則要合併,出新版要重跑一次改動,團隊換人要交接那份 patch。多數團隊評估到這裡就放棄了,改成「這條報出來我們就忽略」,然後那條規則在他們的流程裡實質死掉。能改跟改得起是兩件事。

真正逼你改原始碼的是我們。

所以這不是兩條路,是三種處境:

處境 代表 使用者能做什麼
開源 + 有設定機制 axe-core、pa11y 調參數,原始碼不動
開源 + 沒設定機制 我們現在 改原始碼,或整條關掉
閉源 + 沒設定機制 只能整條關掉

三種處境的階梯圖:最上層是開源且有設定機制,代表工具為 axe-core 與 pa11y,使用者可以調整參數而不動原始碼;中間層是開源但沒有設定機制,標示為本工具現況,使用者只能改原始碼或整條關掉;最下層是閉源且沒有設定機制,使用者只能整條關掉

我們比最差的好,但離最好的還有一段。那一段是我們自己欠的。

所以開源到底是什麼

不是慷慨。

是因為那些判斷除了程式碼以外,我沒有寫在任何地方。

這句話可以當場驗證:README 跟文件裡沒有任何一個閾值;跑 a11y-moda rules show HM1130105E,回給你的是 WCAG 準則、等級、主題、來源、適用階段,就是沒有那個 5

$ a11y-moda rules show HM1130105E

### HM1130105E — 使用語意組件來標記強調的文字或特殊文字
- WCAG SC: 1.3.1
- Level: A
- Topic: structure
- Source: extension
- Scope: scan, lint

那個 5 只存在於一個地方。不打開它,你就不知道那條線畫在哪。

這也是為什麼我不會說「閉源工具不誠實」。閉源工具照樣可以把閾值整理成文件公開,那也是誠實的,只是不用開源做到。我們沒寫文件,所以我們的判斷只有一個出口。

換句話說,開源在我們身上補的是一個自己造成的缺口。這句話講出來不好看,但它比「我們選擇開源因為我們相信透明」準確得多:後者是立場宣示,前者可以查證。

回頭看這六天

前六天一直在講「我們會犯錯」,卻沒講「所以你要能看見並修正我們的錯」。那正好是開源的定義。

前面寫過的 沒有原始碼的話
Day 2 一條規則方向寫反 那個錯會一直錯,永遠沒人發現
Day 3 import 寫錯規則會靜默消失 規則總數少一條,你查不出來
Day 4 那個 16 差一個字元就漏抓 你不會知道有這個門檻存在
Day 5 「55 個連結」是我們挑的 你只能接受,質疑不了
Day 6 對帳分類是我們的判斷 沒人能覆核我們有沒有讀錯

而且整個系列每一句「你可以自己查」都建立在這件事上。Day 3 那段 commit log 如果沒有原始碼可以覆核,它就只是我單方面說的故事,跟任何一篇心得文沒有分別。

開源是地板,不是天花板

那顧問公司圖什麼?

這個問題我被問過幾次,通常帶著善意的困惑:你們做網站,把檢測自家作品的工具送出去,等於把評分標準交給別人。

一個做網站的公司,把檢測自己作品的工具送出去,第一眼看確實不合理。但這個問題問反了:我們賣的從來不是那把尺,是知道怎麼量、量完怎麼修。 一份掃描報告可以自動產生,判斷哪幾條該先修、哪幾條是誤報、哪幾條要動設計而不是動程式碼,那部分自動化不了,而那才是客戶真正付錢買的東西。尺公開之後,我們少了一個可以拿來收費的黑盒子,但換到兩件事:一是不用在簡報裡形容自己多嚴謹,對方自己打開看;二是外面有人幫我們找錯,而檢測工具的價值幾乎完全等於它錯得夠不夠少。

不過我不想把這篇寫成開源好棒棒。我們只做到一半。

看得到那個 5、改得動那個 5,是地板。不必改原始碼就能調,才是 axe 已經站到的位置。 現在的狀況是:你可以改,但你得 fork 一份自己維護,那個門檻對多數人來說跟不能改沒兩樣。

該做的是規則層級的設定檔,讓人不必動程式碼就能調閾值。這件事還沒做。

我也想清楚了為什麼一直沒做:因為自己用的時候不需要。我知道那個 5 在哪、要改哪一行,於是那個缺口對我不存在。寫工具的人最容易看不見的,就是自己不會踩到的門檻。

順帶一個更小但更尷尬的缺口:rules show 不吐閾值。這個工具的定位之一是讓 AI agent 寫程式前先查規則,但查到的東西裡沒有判定門檻 —— agent 只知道「要用語意標記」,不知道「超過 5 個才會被判」。

今天的重點

  • 檢測工具的閾值是立場,不是事實。 那六個數字全是某天某個人畫的線
  • 拍板的不只是數字,還有「主要內容長什麼樣」這種結構假設,而每個網站不一樣
  • 開源不是慷慨,是因為那些判斷沒有寫在程式碼以外的任何地方
  • 開源是地板不是天花板 —— axe 讓你調參數,我們還逼你改原始碼
  • 前六天每一句「你可以自己查」,前提都是這件事

W1 到這裡收尾。明天開始 W2,攤開實作:Python 一行都不是我寫的,那我到底在做什麼。


上一篇
Day 06:規範換版對齊 WCAG 2.2,我以為要補 109 條,實際只有 7 條
下一篇
Day 08:Python 一行都不是我寫的,那我到底在做什麼
系列文
前端不寫 Python,照樣 ship 一把網頁無障礙 CLI9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言