聚焦樣式

焦點指標 (通常以「聚焦環表示」) 可識別您網頁上目前聚焦的元素。對於無法使用滑鼠的使用者,這個指標極為重要,因為它可做為滑鼠指標的支架。

如果瀏覽器的預設焦點指標與您的設計衝突,您可以使用 CSS 重新設定樣式。只要謹記鍵盤使用者!

使用 :focus 一律顯示焦點指標

無論聚焦元素的輸入裝置 (滑鼠、鍵盤、觸控筆等) 或用於聚焦該元素的方法為何,系統都會套用 :focus 虛擬類別。例如,下方的 <div> 具有可聚焦的 tabindex。此外,它的 :focus 狀態也具有自訂樣式:

div[tabindex="0"]:focus {
  outline: 4px dashed orange;
}

無論使用滑鼠點選按鈕,或使用鍵盤分頁前往分頁,<div> 的外觀一律會相同。

遺憾的是,瀏覽器可能與套用焦點功能的方式不一致。元素是否會接收焦點,取決於瀏覽器和作業系統。

舉例來說,下方的 <button> 也有 :focus 狀態的自訂樣式。

button:focus {
  outline: 4px dashed orange;
}

如果在 macOS 的 Chrome 中使用滑鼠按一下 <button>,應會看到自訂的焦點樣式。不過,如果您在 macOS 的 Safari 中按一下 <button>,就不會顯示自訂焦點樣式。這是因為在 Safari 中點選元素時,系統不會接收焦點。

由於焦點的行為不一致,可能需要在不同裝置上進行一些測試,確保使用者可接受您的焦點樣式。

使用 :focus-visible 選擇性顯示焦點指標

每當元素收到焦點,且瀏覽器透過經驗法則判定,對使用者有益時,系統就會套用新的 :focus-visible 虛擬類別。具體來說,如果最近一次的使用者互動是透過鍵盤進行,且按下按鍵未包含中繼、ALT / OPTIONCONTROL 鍵,則 :focus-visible 會相符。

以下範例中的按鈕選擇性會顯示焦點指標。如果使用滑鼠點選按鈕,結果會與首次使用鍵盤按下 Tab 鍵時的結果不同。

button:focus-visible {
  outline: 4px dashed orange;
}

使用 :focus-within 設定焦點元素的父項樣式

當元素本身收到焦點時,或該元素中的其他元素收到焦點時,:focus-within 虛擬類別就會套用至元素。

這可用來醒目顯示網頁的某個區域,讓使用者註意到該區域。舉例來說,使用者選取表單,以及選取任一圓形按鈕時,下列表單都會收到焦點。

form:focus-within {
  background: #ffecb3;
}

顯示焦點指標的時機

在此建議您問問自己:「如果使用行動裝置時按下這個控制項,您會預期裝置是否顯示鍵盤?」

如果答案為「是」,則無論用於聚焦的輸入裝置為何,控制項都可能「一律」顯示聚焦指標。例如 <input type="text"> 元素就是一個很好的例子。無論輸入元素原本如何接收焦點,使用者都必須透過鍵盤將輸入內容傳送至元素,因此建議您一律顯示焦點指標。

如果答案為「否」,控制項可能會選擇性顯示聚焦指標。例如 <button> 元素就是一個很好的例子。如果使用者在滑鼠或觸控螢幕上點選應用程式,代表動作已完成,可能就不需要聚焦指標。不過,如果使用者是使用鍵盤瀏覽,顯示焦點指標會很有幫助,以便使用者決定是否要使用 ENTERSPACE 鍵點選該控制項。

建議不要使用 outline: none

瀏覽器決定繪製焦點指標的時機,實在是很混亂。如果使用 CSS 變更 <button> 元素的外觀,或將元素加上 tabindex,瀏覽器的預設焦點環行為就會進入啟動畫面。

常見的反模式是使用 CSS 移除焦點指標,例如:

/* Don't do this!!! */
:focus {
  outline: none;
}

更好的解決方法是結合 :focus:focus-visible polyfill。下方第一個程式碼區塊示範 polyfill 的運作方式,下方的範例應用程式提供使用 polyfill 變更按鈕上的焦點指標的範例。

/*
  This will hide the focus indicator if the element receives focus via the
  mouse, but it will still show up on keyboard focus.
*/
.js-focus-visible :focus:not(.focus-visible) {
  outline: none;
}

/*
  Optionally: Define a strong focus indicator for keyboard focus.
  If you choose to skip this step, then the browser's default focus
  indicator will be displayed instead.
*/
.js-focus-visible .focus-visible {
  …
}