Day 13 · W2 · 無障礙線 · 難度 ★★★☆☆
本系列由 AI 協作撰寫。 內容、技術判斷、程式碼由 light-design 數位顧問團隊與 Claude 共同產出,最終由作者驗證後 publish。完整協作模式與把關方式見 Day 01。
我沒有在任何一支樣式表裡寫過 outline: none。自家站每一個能用 Tab 停到的地方,都畫了一圈 2px 的外框。
昨天我把鍵盤按過去,一個一個量。33 個停留點裡,有兩個的外框,眼睛看不見。
一句話主軸:焦點外框畫在元件外面,所以它要跟旁邊的顏色比,不是跟元件自己的填色比。
outline-offset 說了算WCAG 2.4.13 焦點外觀的原文寫得很精確,它要求的對比是:
has a contrast ratio of at least 3:1 between the same pixels in the focused and unfocused states
拿同一批像素,比它「聚焦前」跟「聚焦後」的顏色,要到 3:1。
所以真正的問題不是「外框是什麼顏色」,是那圈外框佔用的像素,在聚焦之前是什麼顏色。
outline-offset: 2px; /* 環畫在元件外面 → 那些像素本來是頁面底色 */
outline-offset: -2px; /* 環壓在元件裡面 → 那些像素本來是元件的填色 */
判準短到可以背:offset 為正就比外面,為負就比元件自己。
我第一次量錯了。原本以為「元件的背景」就是那個要比的對象,於是初測一律拿元件自己的填色去比,深色帶上的藍色按鈕算出 1.00,等於在說這圈外框完全不存在。結果打開瀏覽器一看,那圈框清清楚楚,因為它根本沒畫在按鈕上,它畫在按鈕外面。
這跟 Day 10 是同一類錯誤:挑錯了要拿來比的那個背景。Day 10 的版本是漸層文字,這次換成焦點環,公式沒變,變的是「哪一層才是背景」。
第一個掉在線下的是搜尋框,1.54。
.SiteSearch_input:focus {
outline: rgba(10, 71, 176, .25) solid 2px;
outline-offset: 2px;
}
那個 .25 是刻意的。設計上不希望搜尋框被 Tab 到就跳出一圈死藍,所以把品牌藍調淡。
問題是 CSS 裡寫的 rgba(10, 71, 176, .25) 不是螢幕上的顏色。它疊在頁面底色 #fcfdfe 上之後,實際呈現的是 rgb(192, 208, 234),對比 1.54。
在白牆上用白色麥克筆畫記號 —— 筆有下去,痕跡也在,就是看不到。
半透明是焦點框最容易踩的一格:你在編輯器裡看到的是那串 rgba,使用者看到的是合成之後的結果。這件事 Day 10 講的是文字,搬到外框上一模一樣。
第二個是深色價格帶裡的按鈕,1.93。它用的樣式很正常:
a.button:focus-visible {
outline: rgb(10, 71, 176) solid 2px;
outline-offset: 2px;
}
一行 CSS,全站 33 個停留點跑出來的分佈是這樣:
8.11 ×20 白底區塊
7.64 ×11 淺灰底區塊
1.93 ×1 深色價格帶上的按鈕
1.54 ×1 搜尋框
品牌藍對白底 8.11,非常安全。同一個色票,掉到 rgb(32, 34, 37) 的深色帶上就變成 1.93。
這張表還有一件事值得看:33 個停留點全部都有可見的焦點指示,一個都沒漏。也就是說 2.4.7「焦點看得見」這條,我的站是全過的。掉在線下的那兩個,是 2.4.13 才管得到的層次。
有沒有畫,跟看不看得清楚,是兩個不同的準則。 只跑前面那一條,你會拿到一份漂亮的全綠報告。
焦點外框的顏色不能只挑一次。 它得在頁面上所有它可能出現的底色上都成立,而一個站通常有淺底、有深底、有圖片上的浮層。
這也是為什麼規範建議的做法叫「雙色焦點指示器」:內外兩圈不同明度,深底淺底至少有一圈活著。
實務上還有一招更省事:外框不挑顏色,直接用 currentColor 或反色,讓它跟著文字走。文字本來就得對背景合格,外框借它的合格結果。缺點是品牌感會被稀釋,所以這是取捨不是標準答案。
「同一個色票兩種命運」這件事 Day 17 講深色模式時會再遇到一次。

兩個不合格的用的是同一個品牌藍。差別只在它們被畫在什麼顏色上面。
先把一個詞釘住。這系列講的碼號,一律指 MODA 規範裡的檢測碼與稽核評量碼,不是 WCAG 的成功準則編號。兩種號碼常常並排出現,長得也不像:2.4.13 是 WCAG 的,CS3241300E 是碼號。
焦點這件事在碼表上不是一條,是七條,掛在四個成功準則底下:
2.4.7 CS2240700E 使其鍵盤焦點指示具高可見度
FA2240701E 樣式的輪廓與邊框使焦點指示框線不可見
2.4.11 FA2241100E 黏性頁腳或頁首完全遮蔽了焦點元素
2.4.12 CS3241200E 使用滾動邊距(scroll-padding)來消除內容遮蔽
2.4.13 CS3241300E 建立雙色焦點指示器以確保與所有組件有足夠的對比度
CS3241301E 在組件內建立強而明顯的焦點指示框線
GN3241302E 使用作者提供的可見焦點指示框線
右邊那一串看起來像流水號。規範裡有一整節在定義它是怎麼組出來的。
稽核評量碼格式為3碼文字與7碼數值,如:XX3141099E,此10碼字符共可分為5項
五項是這五段:
CS 網頁科技
3 檢測等級
2413 成功準則
00 流水號
E 類型
每一段的可能值:

中間四碼就是 WCAG 的成功準則號。碼號跟 WCAG 準則號會被搞混,是因為前者真的把後者包在裡面。
我照這份格式把 115.11 的 244 條碼號全部拆過一次,244 條全部解得開。規範自己也報了總數:可用軟體檢測的檢測碼 28 條、需人工稽核的稽核評量碼 216 條,加起來 244 —— 跟我手上那份碼表對得起來。
所以要知道一條是 A 還是 AAA,不用查表,看第三個字元就好。 焦點這一家七條裡,FA2241100E 的第三個字元是 2,AA。黏性頁首把焦點元素整個蓋掉,那不是加分題,是義務。
至於那些等級是怎麼來的:2.4.7 在 WCAG 2.1 與 2.2 都是 AA;2.4.11 是 2.2 新增的 AA;2.4.12 與 2.4.13 是 2.2 新增的 AAA。Day 6 已經確認過,換版是碼表位移,不是義務降級。
outline: none 不是罪,沒補回來才是先幫這行 CSS 平反。當年大家會寫它,是因為 :focus 對滑鼠點擊一樣生效 —— 按鈕被點一下就套一圈框,設計師會抓狂。
:focus-visible 就是為了這件事存在:瀏覽器自己判斷這次聚焦要不要給視覺提示,鍵盤 Tab 給,滑鼠點不給。
button:focus { outline: none; }
button:focus-visible { outline: 3px solid #0b6b65; outline-offset: 2px; }
寫探針時我在這裡踩過一個坑:getComputedStyle(el, ':focus-visible') 是無效的,第二個參數只吃偽元素(::before 那種),不吃偽類。Chromium 不會報錯,它會安靜地退回非聚焦樣式,於是你得到一堆「這個元素沒有焦點指示」的假陰性。
正確做法是先按 Tab 讓元素真的聚焦,再讀它的一般計算樣式 —— 那時候該套的那一層已經在裡面了。
FA2241100E 對應的 2.4.11 是這一家裡最容易中的一條,因為它跟你的 CSS 寫得好不好無關。
瀏覽器會把聚焦的元素捲進可視範圍,但它不知道你的頁首是 position: sticky。捲到位之後,元素確實在畫面上,蓋在它上面的是那條頁首。
省事的解法只有一行:
:target, :focus-visible { scroll-margin-top: 5rem; }
探針怎麼判:拿聚焦元素的外框取四個點,看每個點最上層是哪個元素;如果那個元素的祖先鏈上有 sticky 或 fixed,這一點算被蓋。四點全被蓋等於整個被蓋,那是 2.4.11 的 AA;只要有一點被蓋就違反 2.4.12 的 AAA。
這個分界不是我發明的,是準則自己的字面差別:一個寫 entirely hidden,一個寫 no part。

聚焦前後同一批像素的對比。offset 的正負決定了「聚焦前」是誰。
CS3241301E 量的是外框夠不夠粗,門檻 2px。它從來沒量過對比。
而它報出來的訊息裡有這麼一句:「建議 outline 至少 2px,並與相鄰色彩具足夠對比。」
後半句是寫給人看的建議,程式一個字都沒有執行。 真正管對比的是 CS3241300E,碼表上有,我沒實作。更難看的是:探針早就把 outline_color 收進來了,一直放著沒有任何規則在用。
補完規則之後重掃,只抓到 1 個。另一個去哪了?
Tab 走訪在第 11 個停留點就停了。判斷「是不是繞回起點」用的 key 是 標籤|選擇器|文字 的組合,導覽列有好幾個文字相同的連結,第一個撞名就 break。33 個停留點只走了 11 個,後面的問題全部看不到。
改成兩個真訊號才停:焦點按了 Tab 沒有移動,或是回到第一個停留點。
這節的重點不是我補了一條規則。 是你手上那套自動化檢查,很可能也只量了粗細那一半,而它的輸出還會用「並與相鄰色彩具足夠對比」這種句子,把沒做的那一半蓋過去。
手動 Tab 一遍,看焦點停在哪、看不看得見。這件事目前沒有工具能完全代勞。
outline: none 沒寫,不代表焦點看得見,補了也不一定夠outline-offset 的正負決定「聚焦前」是誰rgba(..., .25) 想柔和,合成之後只剩 1.54FA2241100E 是 AA,黏性頁首蓋住焦點是義務不是加分明天 Day 14:我的工具會自己去按別人網站上的按鈕,所以我列了一份「不准按」的清單。然後我發現,真正會把東西送出去的那顆鍵,根本不在上面。