iT邦幫忙

2026 iThome 鐵人賽

DAY 24
0
Modern Web

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

Day 24:把瀏覽器縮到 320px,我的網站有幾頁會橫著捲

  • 分享至 

  • xImage
  •  

Day 24 · W4 · 無障礙線 · 難度 ★★☆☆☆

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

把瀏覽器拉到 320px 寬,然後往右邊拉一下。拉得動,這條就不過。

Day 01 的承諾清單裡有一句「螢幕縮到 320px,版面會不會爆掉」,今天回收。答案先講:自家站 30 頁,零頁。然後我把六個常見的兇手一個一個放回去,看工具抓不抓得到,五個中。

一句話主軸:320px 不是哪支手機的寬度,是規範的門檻;工具只會告訴你這一頁捲了,是誰撐開的,得自己找。

320 這個數字從哪來

WCAG 1.4.10 的原文:垂直捲動的內容,在 320 CSS 像素的寬度下不需要水平捲動。條文自己註明了這個數字的來歷:1280px 寬的畫面放大到 400%,就是 320。

所以它跟手機沒有直接關係。它管的是把畫面放大四倍的人,低視能的使用者常這樣用桌機。放大四倍之後如果每一行都要左右拉,一段文字讀完要拉幾十次。手機剛好也落在這個寬度附近,所以修了一邊另一邊也會好,但條文的出發點是放大,不是裝置。

規則庫裡 responsive 這個主題有 23 條,是 22 個主題裡最大的一組,第二名的表單 21 條。這 23 條裡,1.4.10 的這一條最硬,也最好驗:門檻是一個數字,結果是一個布林。

我的站:三十頁,零頁

工具怎麼驗:開瀏覽器,把視窗設成 320px 寬,讀 documentElement.scrollWidthclientWidth。前者是內容實際多寬,後者是視窗多寬。前者大於後者,就是有東西超出去了。

320px 視窗示意圖:一個 320px 寬的視窗框,裡面一個 640px 寬的區塊從右邊伸出去;視窗寬標示 clientWidth 320,內容寬標示 scrollWidth 648,兩者的差就是橫向捲軸的長度;下方註明工具只比這兩個數字,不看是哪個元素

兩個數字,一個比較。工具做的事就這麼多。

Day 22Day 23 那兩份 30 頁的報告,這條規則一筆都沒報。首頁、方案、聯絡、作品列表加四篇案例、部落格列表加 18 篇文章、sitemap、搜尋頁,30 頁在 320px 下都沒有橫向捲軸。

同一個家族倒是有話說:11 頁有 info,說頁面含長字串但沒設 overflow-wrap。頁沒捲,是因為那些字串目前剛好沒有長到超出 320;規則提醒的是那條防線不存在。這種 info 跟下面第二個兇手是同一件事,只是還沒發作。

這裡要講一個條件:這條只在開瀏覽器時跑。Day 04 說過 146 條裡 50 條不用瀏覽器,這條不在那 50 條裡,靜態掃描直接跳過,報告上什麼都不會有。看到沒報,先確認掃描有沒有開 --render

零頁沒什麼好寫的。所以我做了七個示範頁。

把六個兇手放回去

規劃這篇的時候我列了六種最常撐開容器的寫法,每一種做成一頁,其他什麼都沒有,掃一次:

七個示範頁在 320px 下的結果表:寫死 640px 的區塊,頁寬 648,工具報 fail;一段不斷行的長網址,頁寬 1121,fail;五格短文字的表格,頁寬 320,通過;八欄數字的表格,頁寬 491,fail;同一張八欄表格包在 overflow-x auto 的容器裡,頁寬 320,通過;一行長程式碼的 pre,頁寬 820,fail;絕對定位 left 300 寬 200 的區塊,頁寬 500,fail;width 100vw 的區塊配一頁長內容,頁寬 328,fail。每列附修法

六個兇手五個中。沒中的那個是我做壞了,不是它無辜。

沒中的是表格。我第一版做了五格短文字,掃出來 320,通過,因為每一格自己換行了。換成八欄數字,數字不換行,頁寬 491,中。表格不是天生會撐開,是欄位多到換不了行才會。

長字串那頁是一段網址,1121px,六個裡最寬。中文本來就逐字換行,會撐開的是英數:網址、雜湊、沒有空白的識別碼。這種內容的修法是斷字,不是捲:overflow-wrap: anywhere 讓瀏覽器在任何字元之間都可以斷,一段網址斷在哪裡讀者都不會損失什麼。修法要看內容是什麼:文字要斷,表格要捲。格子裡的數字斷成兩行就讀錯了,所以表格是包進可捲的容器,捲動關在那個元素裡,下一節講。絕對定位那頁是 left: 300px 加 200px 寬,元素本身不大,位置把它推出去了,常見於裝飾用的圖形跟沒算好位置的提示框。

我原本以為 100vw 就是視窗寬,等於 100%。結果它多了 8px,那是捲軸的寬度。內容一長出現捲軸,100vw 還是算整個視窗,於是每一頁都多出一條捲軸寬的橫向捲動。這一個最陰險,因為版面看起來完全正常,只是右邊永遠可以再拉一點點。

這像行李箱塞到關不起來。問題通常是其中一件東西,不是整個箱子太小。

工具只說捲了,不說是誰

報告裡這條的內容是「內容寬 648px,視區 320px」。就這樣。它不告訴你是哪個元素。

要找元素,得回瀏覽器。把視窗縮到 320,在 console 跑這一段:

const vw = document.documentElement.clientWidth;
const hits = [];
for (const el of document.querySelectorAll('body *')) {
  const r = el.getBoundingClientRect();
  const spill = Math.max(r.right, el.scrollWidth + r.left);  // 盒子超出,或內容在盒子裡溢出
  if (spill > vw + 1) hits.push({ el, spill: Math.round(spill) });
}
// 祖先只是被子元素撐開的不算,只留最深的
hits.filter(h => !hits.some(o => o !== h && h.el.contains(o.el)))
    .forEach(h => console.log(h.el, h.spill + 'px'));

第五行有兩個量。getBoundingClientRect().right 抓的是盒子本身超出視窗,寫死寬度、絕對定位、100vw 都是這種。scrollWidth 抓的是盒子沒超出、但內容在盒子裡溢出,長網址跟 pre 是這種,只看盒子會漏掉。第一版我只寫了前者,七頁裡兩頁找不到兇手,補了後者才全中。

最後那個過濾是為了不要整條祖先鏈都被列出來。八欄表格那頁,tabletheadtr 全都超出視窗,但撐開的是格子,所以只留 th

這段不在工具裡。工具的工作是在 30 頁裡告訴你哪一頁捲了,找元素是那一頁打開之後的事。

例外不是免死金牌

1.4.10 有例外:需要二維版面才能使用或理解的內容。規範的說明文件舉的例子是圖片、地圖、圖表、影片、遊戲、簡報、資料表格,還有必須把工具列固定在畫面上的介面。

例外的正確用法不是「所以表格可以橫捲」,是「表格自己捲,整頁不動」。示範頁裡那張八欄表格包進 overflow-x: auto 的容器之後,頁寬回到 320,工具過了;但 console 那段還是會把 th 列出來,因為格子確實超出視窗,只是捲動被關在容器裡。兩個結果都對,量的東西不同。

台灣的碼表在這裡比 WCAG 講得更具體。1.4.10 對應的檢測碼原文:「在垂直捲動的頁面中,可水平捲動的區域面板,其設計本身也必須被容納於 320 CSS 像素的寬度內。」它直接點名「可水平捲動的區域面板」,也就是那個容器本身不能比 320 寬,裡面的東西才可以捲。Day 05 的三層模型再用一次:WCAG 給門檻,碼表把例外的邊界畫出來,工具量整頁有沒有橫捲。工具量的是第一層,碼表那句要人看容器。

程式碼區塊不在規範的例外清單上。實務上大家都讓 pre 自己捲,那是慣例,不是條文給的豁免;Day 10 講過承認限制要配替代方案,這裡的替代方案是讓長行可以換行,或至少讓捲動只發生在那個區塊。

1.4.4 是另一條

跟 1.4.10 最常被搞混的是 1.4.4:文字放大到 200% 不能失去內容或功能。一個是縮小視窗,一個是放大文字,方向相反,壞法也不同。放大文字會壞的是寫死高度的容器,文字變大之後被截掉;縮小視窗會壞的是寫死寬度的容器。

碼表對 1.4.4 有兩條,工具都有實作,但要老實講它們是啟發式:一條看 viewport 的 meta 有沒有寫 user-scalable=nomaximum-scale=1,那會直接擋掉使用者放大;另一條數樣式表裡 width 用 px 的次數跟用百分比、vw 的次數,px 太多就提醒。工具沒有真的把頁面放大到 200% 再量,那要另一個探針,目前沒有。

所以這兩條在報告上是 info,不會是 fail。1.4.10 那條是真的量了才報,這兩條是看到跡象才提醒。同一份報告裡,兩種不同強度的話。自家站這兩條也都沒報:viewport 沒擋縮放,樣式表裡的 px 寬度沒多到觸發門檻。

今天的重點

  • 320px 是 1280 放大 400%,管的是放大畫面的人,不是哪支手機。
  • 自家站 30 頁零頁橫捲;這條只在開瀏覽器時跑,靜態掃描不會報。
  • 六個兇手五個中:寫死寬度、長字串、pre、絕對定位、100vw;表格要欄位多到換不了行才會。
  • 工具只說哪一頁捲了,找元素要回瀏覽器;只看盒子會漏掉溢出的內容,兩個量都要抓。
  • 例外是讓元素自己捲,不是整頁捲;碼表原文直接點名容器本身要塞進 320。

明天 Day 25:量完站,回頭量 AI。同一個需求各寫三份。我讓 AI 先查規範再寫,差別只在它查到的那幾條。


上一篇
Day 23:我沒教 AI 怎麼修,我教它怎麼證明修好了
系列文
前端不寫 Python,照樣 ship 一把網頁無障礙 CLI24
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言