使用 Tabindex 修改 DOM 順序
原生元素 DOM 位置提供的預設分頁順序相當方便,但有時您或許會想修改分頁順序,而在 HTML 中實際移動元素未必是最佳或可行的解決方案。在這種情況下,您可以使用 tabindex
HTML 屬性明確設定元素的分頁位置。
tabindex
可套用至任何元素,但不一定適用於所有元素,且會採用一個整數值範圍。透過 tabindex
,您可以為可聚焦的網頁元素指定明確的順序、將不可聚焦的元素插入分頁順序,並從分頁順序中移除元素。例如:
tabindex="0"
:在自然的定位點順序中插入元素。按下 Tab
鍵就能聚焦元素,呼叫其 focus()
方法則可聚焦元素
<custom-button tabindex="0">Press Tab to Focus Me!</custom-button>
tabindex="-1"
:從自然分頁標籤順序中移除元素,但呼叫其 focus()
方法仍可聚焦該元素
// TODO: DevSite - Code sample removed as it used inline event handlers
// 待辦事項:DevSite - 因使用內嵌事件處理常式而移除的程式碼範例
tabindex="5"
:如果分頁標籤索引數量大於 0,系統就會將元素跳至自然分頁順序的前方。如果多個定位索引值大於 0,分頁順序就會從大於 0 的最低值開始,並依此往上排序。使用大於 0 的定位索引會視為反模式。
<button>I should be first</button>
<button>And I should be second</button>
<button tabindex="5">But I jumped to the front!</button>
在標頭、圖片或文章標題等非輸入元素中更是如此。在這些類型元素中新增 tabindex
會產生反效果。如果可以,最好整理原始碼,讓 DOM 序列提供邏輯分頁順序。如果您使用 tabindex
,請將其限制為自訂互動控制項,例如按鈕、分頁、下拉式選單和文字欄位,也就是使用者可能會希望輸入的元素。
您不必擔心螢幕閱讀器使用者缺少重要內容,因為其沒有 tabindex
。即使內容非常重要 (例如圖片),如果使用者無法與其互動,根本沒有理由將該內容設為可聚焦。只要您提供適當的 alt
屬性支援,螢幕閱讀器使用者仍能瞭解圖片的內容,我們稍後會說明。
在網頁層級管理焦點
在以下情況中,tabindex
不僅實用,也是一種必要。那麼,您可以建構包含不同內容區段的完善單一網頁,而不是所有內容區段同時顯示。在這類頁面中,點選導覽連結可能會變更顯示內容,而不重新整理頁面。
發生這種情況時,您可能會識別所選內容區域,為其提供 -1 的 tabindex
,這樣便不要以自然分頁順序顯示,並呼叫其 focus
方法。這項技術稱為「管理焦點」,可讓使用者感知的背景資訊與網站的視覺內容保持同步。
管理元件中的焦點
在頁面上變更內容時管理焦點很重要,但有時需要在控制層級管理焦點 (例如建構自訂元件時)。
我們來看看原生 select
元素。可接收基本焦點,但一旦取得,您就可以使用方向鍵顯示其他功能 (可選取的選項)。如要建構自訂 select
元素,建議您公開這些相同類型的行為,讓主要仰賴鍵盤的使用者仍可與控制項互動。
<!-- Focus the element using Tab and use the up/down arrow keys to navigate -->
<select>
<option>Aisle seat</option>
<option>Window seat</option>
<option>No preference</option>
</select>
瞭解要實作的鍵盤行為並不容易,但您可以參考一些實用文件。無障礙網際網路應用程式 (ARIA) 編寫做法指南列出元件類型,以及這類元件支援的鍵盤動作類型。我們稍後會更詳細地介紹 ARIA,但現在我們先使用指南,協助我們將鍵盤支援加入新的元件。
也許您正在處理一些與一組圓形按鈕類似的新自訂元素,但有獨特的外觀和行為。
<radio-group>
<radio-button>Water</radio-button>
<radio-button>Coffee</radio-button>
<radio-button>Tea</radio-button>
<radio-button>Cola</radio-button>
<radio-button>Ginger Ale</radio-button>
</radio-group>
如要判斷所需的鍵盤支援類型,請參閱 ARIA 編寫做法指南。第 2 節包含設計模式清單,該清單是無線電群組的特性表格,也就是與新元素最相符的現有元件。
如表格所示,系統可能需要支援的常見鍵盤行為之一就是向上/向下/向左/向右鍵。如要將這個行為新增至新元件,我們會使用「核准定位索引」技術。
旋轉分頁索引的運作方式是將所有子項的 tabindex
設為 -1 (目前使用中的子項除外)。
<radio-group>
<radio-button tabindex="0">Water</radio-button>
<radio-button tabindex="-1">Coffee</radio-button>
<radio-button tabindex="-1">Tea</radio-button>
<radio-button tabindex="-1">Cola</radio-button>
<radio-button tabindex="-1">Ginger Ale</radio-button>
</radio-group>
接著,此元件會使用鍵盤事件監聽器,判斷使用者按下哪個按鍵。如果發生這種情況,該元件會將先前聚焦的子項 tabindex
設為 -1、將待聚焦的子項 tabindex
設為 0,並對其呼叫聚焦方法。
<radio-group>
// Assuming the user pressed the down arrow, we'll focus the next available child
<radio-button tabindex="-1">Water</radio-button>
<radio-button tabindex="0">Coffee</radio-button> // call .focus() on this element
<radio-button tabindex="-1">Tea</radio-button>
<radio-button tabindex="-1">Cola</radio-button>
<radio-button tabindex="-1">Ginger Ale</radio-button>
</radio-group>
當使用者到達最後一個 (或第一個,取決於他們移動焦點的方向) 的子項時,就會循環顯示第一個 (或最後一個) 子項。
您可以將完成的範例試用如下。在開發人員工具中檢查元素,觀察分頁索引從某個無線電移至下一個無線電。
// 待辦事項:DevSite - 因使用內嵌事件處理常式而移除的程式碼範例
您可以在 GitHub 上查看此元素的完整原始碼。
視窗和鍵盤陷阱
有時在管理焦點時,您可能會遇到難以離開的情況。假設有自動完成小工具,嘗試管理焦點及擷取分頁行為,但會防止使用者離開小工具,直到小工具完成為止。這就是所謂的鍵盤陷阱,可能會讓使用者感到非常困擾。Web AIM 檢查清單的第 2.1.2 節已解決這個問題,指出鍵盤焦點一律不得鎖定或影響到單一頁面元素。讓使用者只要用鍵盤就能來回瀏覽所有頁面元素。
奇怪的是,有時這個行為確實符合預期,例如強制回應視窗。一般而言,在顯示互動視窗時,您不希望使用者存取該互動視窗背後的內容。您可以新增重疊元素,以視覺化的方式蓋住頁面,但這樣並不會阻止鍵盤焦點意外離開視窗之外。
在這類情況下,您可以實作臨時鍵盤陷阱,確保只有在顯示互動視窗時能捕捉焦點,然後在關閉互動視窗時,將焦點還原到先前聚焦的項目。
有一些提案 (包括
<dialog>
元素) 可讓開發人員更輕鬆地達成此目標,但這些提案目前尚未支援廣泛的瀏覽器。
假設這是由 div
代表的強制回應對話方塊,其中包含幾個元素,以及另一個代表背景重疊的 div
。以下逐步說明在這種情況下實作暫時性鍵盤繞圈的必要基本步驟。
- 使用
document.querySelector
即可選取互動視窗和疊加層 div,並儲存其參照。 - 互動視窗開啟時,儲存互動視窗開啟時聚焦元素的參照,以便您將焦點回傳至該元素。
- 在互動視窗開啟時,使用 keydown 事件監聽器擷取按鍵。您也可以監聽背景重疊的點擊,並在使用者點擊背景重疊時關閉互動視窗。
- 接著,在互動視窗中取得可聚焦元素集合。第一個和最後一個可聚焦元素將做為「前段」,讓您知道何時要將焦點向前或向後轉動,以便停留在互動視窗中。
- 顯示互動視窗,並將焦點移至第一個可聚焦的元素。
- 當使用者按下
Tab
或Shift+Tab
時,視需要向前或向後移動焦點,在最後一個或第一個元素上輪流。 - 當使用者按下
Esc
時,關閉互動視窗。這種做法非常實用,可讓使用者在不搜尋特定關閉按鈕的情況下關閉互動視窗,而且即使是使用滑鼠的使用者也能因此受益。 - 關閉互動視窗後,請隱藏該互動視窗和背景重疊,然後將焦點還原為先前儲存的元素。
這項程序提供可用且不會讓人感到不悅的強制回應視窗,讓所有人都能有效使用。