iT邦幫忙

2026 iThome 鐵人賽

DAY 15
0
Modern Web

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

Day 15:我幫大部分的圖決定了它不用被唸出來

  • 分享至 

  • xImage
  •  

Day 15 · W3 · 無障礙線 · 難度 ★★★☆☆

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

昨天我把自家站六個頁面的圖片全部撈出來數。

<img> 總數        155
沒有 alt 屬性       0
alt=""            133
有文字的 alt        22

一張都沒漏。 在「圖片有沒有替代文字」這條規則上,我的站是滿分。

滿分的原因是我把八成的圖片宣告成裝飾,螢幕報讀軟體整頁跳過它們。

一句話主軸:alt="" 是一個決定,不是一個預設值。

空字串跟沒寫,是相反的兩件事

先講清楚這兩行不一樣。

<img src="deco.png">              沒有 alt:報讀軟體只好唸檔名
<img src="deco.png" alt="">       空 alt:報讀軟體直接跳過

沒寫 alt,輔助科技不知道該不該講,多數會退而求其次唸出檔案名稱。deco-final-v3.png 唸出來是雜訊。

寫了 alt="",等於明講「這張圖沒有資訊,跳過它」。那是正確且必要的用法。

差別只有兩個引號,意思完全相反:一個是沒填,一個是填了「不需要」。

我以為八成有問題,量完發現不是

寫這篇之前我的假設是:這麼高的比例,裡面一定有被誤殺的。

所以我加了三個檢查。三個都沒抓到東西。

空 alt 且在連結裡、而那個連結沒有其他文字        0
空 alt 且在 <figure> 裡(有圖說卻不描述圖)      0
空 alt 但完全沒有相鄰文字                       0

第一個是真正的缺陷型態:一張圖是連結裡唯一的內容,alt 又是空的,那個連結就沒有名字,報讀軟體只會唸「連結」兩個字。

我的站上是 0 個。我原本以為會抓到一整排。

把尺寸攤開來看就合理了:

小於 32×32      12    圖示、箭頭、分隔符號
小於 100×100    42    logo、小徽章、頭像框
小於 200×200    20    卡片內的裝飾元素
200×200 以上    59    卡片主視覺

前面 74 張本來就是裝飾。真正值得討論的是最後那 59 張 —— 其中 35 張是 504×284,那個尺寸不是圖示,是卡片封面。

我把它們的相鄰文字全部撈出來,59 張每一張旁邊都有標題。那個標題已經把這張卡片在講什麼說完了。這種情形下寫 alt 反而更糟,報讀軟體會先唸圖片描述再唸一次標題,同一件事聽兩遍。

自家站六個頁面 155 張圖片的替代文字盤點:沒有 alt 屬性的 0 張、alt 為空字串的 133 張佔百分之八十六、有文字內容的 22 張且只有 15 種不重複寫法。下半部是 133 張空 alt 的尺寸分佈,小於 32 乘 32 有 12 張、小於 100 乘 100 有 42 張、小於 200 乘 200 有 20 張、200 乘 200 以上有 59 張。針對這 59 張大圖做三項缺陷檢查,包括是否位於沒有其他文字的連結內、是否位於 figure 元素內、是否完全沒有相鄰文字,三項結果皆為 0,且 59 張全部都有相鄰的可讀標題

八成六看起來很高,攤開尺寸就合理了。真正要討論的只有最大的那 59 張。

那 133 張,是決定不是預設

我原本想在這篇留一個開放問題:那些空字串,有多少是有人想過的,有多少是框架預設帶進來的。

從 HTML 看得出來。

<img alt="" aria-hidden="true" role="presentation" ...>
alt=""                    133
  其中 aria-hidden=true    133
  其中 role=presentation   133

三個屬性,133 張全部都有。 沒有人會不小心同時寫三個。那是元件層級寫死的,是一個做過的決定。

判準只有一句話

把這張圖拿掉,這個地方還講不講得清楚?

講得清楚,就 alt=""。講不清楚,圖裡有的資訊就得補進 alt。

卡片封面圖 + 標題        標題已經說完 → alt=""
單獨一張流程圖           圖裡的資訊只有圖裡有 → 必須描述
圖示按鈕(只有圖沒有字)   圖就是那顆按鈕的名字 → 一定要寫
主視覺壓著標題文字        通常是氣氛 → alt="",但圖裡若有專屬資訊要搬出來

第三種是 Day 14 講過的:只有圖示的按鈕,aria-label 是機器唯一讀得到的意圖。

在白牆上貼一張說明卡。 牆上已經寫了字,你再貼一張寫同樣內容的卡片,不會讓人看得更清楚,只會擋住一部分牆。

該檢查的是有寫的那 22 個

真正可議的不是空的那 133 張,是有寫的那 22 張。它們只有 15 種:

x6  通過AAA無障礙網頁檢測
x3  活動網站範例畫面
x1  睞特數位顧問首頁主視覺
x1  鋼品製造業 大頭照
x1  Iphone
x1  Line API
x1  ERP 整合

前面幾個沒問題。鋼品製造業 大頭照 還帶了脈絡,聽到的是「一位鋼品製造業客戶的頭像」,比只寫「頭像」有用。

後面三個是可議的。 IphoneLine APIERP 整合 是能力清單旁邊的圖示,而清單本身就寫著那些字。照剛才那條判準,它們應該是 alt=""。現在的寫法會讓報讀軟體唸兩次:「Line API,Line API」。

順帶,Iphone 的正確寫法是 iPhone在一個會被照著唸出來的地方,拼寫錯誤是聽得出來的。

我的工具對這 155 張圖,一個字都沒說

同一次掃描,六個頁面,工具報了 13 種問題 —— 焦點對比、滾動邊距、黏性頁首遮蔽。替代文字相關的:0 條。

我第一個念頭是「這題自動化補不起來」。去翻程式碼才發現,補得起來,規則早就在那裡。

HM1110112E   對於輔助科技應當要忽略的圖片,使用空字串作為替代文字
             判準:pass 純裝飾 / fail 脈絡暗示承載資訊 / unsure 判不出來時必選

那正是我這篇手動做的事。它沒說話,不是因為它不會,而是因為六件事。

六層都合理,疊起來是沉默

我把那條規則從頭追到尾,列出它為什麼在我的站上永遠不會有輸出:

0  尊重作者宣告    看到 aria-hidden 就跳過        我的站 133/133 全被濾掉
1  分工            title 那半由 HM1110106C 負責   避免同一件事報兩次
2  抽樣上限        每頁最多看 8 張                 控制模型呼叫成本
3  報一則就停       第一個 fail 之後 return        避免洗版
4  等級降為 info    這題主觀,不進 fail 計數        保守
5  沒接模型         直接返回,什麼都不報            我那次掃描沒帶模型參數

沒有一層是 bug。 每一個決定單獨看都對,而且都有人為它辯護得出來。

尊重作者的宣告是對的 —— 人家都明寫「請忽略這張圖」了,再去問模型「它是不是真的裝飾」,等於不信任作者。避免同一件事報兩次是對的,不然使用者會看到重複項目。控制成本是對的,一頁一百張圖就是一百次呼叫。主觀的事降級成參考是對的,不該讓判不準的項目拉高失敗數。

問題是這六層從來沒有被放在一起看過。 每一層都是在解決自己那層的問題時加上去的,而沒有人回頭問:全部加起來之後,這條規則還剩下多少機會說話。

六個篩子疊在一起,每一個網目都合理,疊起來什麼都過不去。

第 5 層我今天修掉了。現在沒接模型時,報告每頁會多一行:

有 44 條規則需要語言模型才能判定,本次未提供模型參數,因此完全沒有執行。
這些項目在本報告中既不是通過也不是失敗,是未檢查。

「沒有發現問題」跟「沒有檢查」在報告上長得一模一樣,而第二種讀法會害人。這跟 Day 12 那個取捨是同一件事:能被看見的失敗,比看不見的成功安全。

剩下五層我沒有動。它們不是錯的,只是需要被寫下來 —— 一份報告應該讓人知道它的檢查涵蓋到哪裡為止。

替代文字規則被六層設計決定逐層過濾的示意圖:第零層尊重作者宣告,看到 aria-hidden 屬性就跳過,自家站 133 張圖全數在此被濾掉;第一層是分工,標題屬性那半交給另一個檢測碼負責;第二層是抽樣上限,每頁最多檢查八張圖片以控制成本;第三層是報一則就停止,遇到第一個失敗後即返回;第四層把嚴重度降為資訊等級,不計入失敗總數;第五層是未提供模型參數時直接返回且不留任何訊息。六層每一層單獨看都有合理理由,疊加起來的結果是這條規則在該網站上完全沒有輸出

六個篩子疊在一起,每一個網目都合理,疊起來什麼都過不去。

模型其實判得準,是規則沒讓它說完

為了確認不是模型不行,我做了一頁刻意寫壞的測試頁,答案我自己知道,然後逐張問。

圖表配「各季營收成長」        預期 fail    實際 fail   ✔
人物照配「創辦人 王大明」      預期 fail    實際 fail   ✔
空 alt 卻帶 title 的圖表     預期 fail    實際 fail   ✔
漸層背景,旁邊沒有文字        預期 pass    實際 pass   ✔
分隔線配一段服務說明          預期 pass    實際 pass   ✔

五個全中,包括「分隔線在服務項目的脈絡中僅作視覺區隔」這種要看上下文的判斷。

但整條規則跑同一頁,只報了一則,停在第一個案例。後面那兩個真正該抓的圖表跟人物照,一個都沒出現在報告上。

判斷力沒問題。問題是報告只讓它說一句話。

而這件事在真實網站上只會更嚴重。fixture 上三個違規報一個,已經漏了三分之二;一個有幾十張圖的頁面,比例只會更難看。

我沒有動那兩個上限。抽樣跟只報一則都是為了成本與可讀性設的,現在憑感覺調數字,只是把一個猜測換成另一個猜測。 要調得先有真實的成本資料。

今天的重點

  • alt="" 跟沒有 alt 是相反的兩件事,一個是沒填,一個是填了「不需要」
  • 判準不是圖多大、多重要,是「拿掉之後這個地方還講不講得清楚」
  • 三個屬性同時出現就是決定,不是框架隨手帶的預設值
  • 一條規則可以同時被六個合理的設計決定折掉,而每一層都有正當理由
  • 判不出來跟沒去判,在報告上長得一樣,這件事要主動講出來
  • 模型判得準,但規則只讓它說一句話

明天 Day 16:圖檢查完了,接下來輪到連結。我原本要抓的是「了解更多」這種沒在說話的連結,一個都沒找到。問題出在另一頭。


上一篇
Day 14:我列了一份「不准按」的清單,然後發現送出鍵不在上面
系列文
前端不寫 Python,照樣 ship 一把網頁無障礙 CLI15
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言