可鍵盤導航的 JavaScript 元件
Web 應用程式通常使用 JavaScript 來模仿桌面部件,例如選單、樹狀檢視、富文字欄位和選項卡面板。這些部件通常由 <div> 和 <span> 元素組成,這些元素本質上不提供與其桌面對應物相同的鍵盤功能。本文件描述了使 JavaScript 部件可鍵盤訪問的技術。
使用 tabindex
預設情況下,當人們使用 Tab 鍵瀏覽網頁時,只有互動式元素(如連結、表單控制元件)才能獲得焦點。透過 tabindex 全域性屬性,作者也可以使其他元素獲得焦點。當設定為 0 時,元素可以透過鍵盤和指令碼獲得焦點。當設定為 -1 時,元素可以透過指令碼獲得焦點,但它不會成為鍵盤焦點順序的一部分。
使用鍵盤時元素獲得焦點的順序,預設是源順序。在特殊情況下,作者可能希望重新定義順序。為此,作者可以將 tabindex 設定為任何正數。
警告: 避免為 tabindex 使用正值。具有正 tabindex 的元素會出現在頁面上預設互動式元素之前,這意味著頁面作者在使用一個或多個正 tabindex 值時,必須為頁面上所有可聚焦的元素設定(並維護)tabindex 值。
下表描述了現代瀏覽器中 tabindex 的行為
tabindex 屬性 |
可透過滑鼠或 JavaScript (element.focus()) 聚焦 |
Tab 可導航 |
|---|---|---|
| 不存在 | 遵循元素的平臺約定(表單控制元件、連結等為“是”)。 | 遵循元素的平臺約定。 |
負值(例如 tabindex="-1") |
是 | 否;作者必須透過 focus() 方法響應箭頭鍵或其他按鍵來聚焦該元素。 |
零(例如 tabindex="0") |
是 | 在文件中相對於元素位置的 Tab 順序中(請注意,<a> 等互動式元素預設具有此行為,它們不需要該屬性)。 |
正值(例如 tabindex="33") |
是 | tabindex 值決定了該元素在 Tab 順序中的位置:較小的值將比較大的值更早地將元素放置在 Tab 順序中(例如,tabindex="7" 將出現在 tabindex="11" 之前)。 |
非原生控制元件
像 <a>、<input> 和 <select> 這樣的原生 HTML 互動式元素已經是鍵盤可訪問的,因此使用它們是使元件支援鍵盤的最快途徑。
透過新增 tabindex 的 0 值,作者也可以使 <div> 或 <span> 元素鍵盤可訪問。這對於使用 HTML 中不存在的互動式元素的元件特別有用。
分組控制元件
對於選單、選項卡列表、網格或樹狀檢視等元件的父元素分組,父元素應在 Tab 順序中(tabindex="0"),並且每個後代選項/選項卡/單元格/行都應從 Tab 順序中移除(tabindex="-1")。使用者應能夠使用箭頭鍵導航後代元素。(有關典型小部件通常預期的鍵盤支援的完整描述,請參閱 WAI-ARIA Authoring Practices。)
下面的示例展示了這種技術在巢狀選單控制元件中的使用。一旦鍵盤焦點落在包含的 <ul> 元素上,JavaScript 開發人員就必須以程式設計方式管理焦點並響應箭頭鍵。有關在元件內管理焦點的方法,請參閱下面的“管理組內焦點”。
<ul id="mb1" tabindex="0">
<li id="mb1_menu1" tabindex="-1">
Font
<ul id="fontMenu" title="Font" tabindex="-1">
<li id="sans-serif" tabindex="-1">Sans-serif</li>
<li id="serif" tabindex="-1">Serif</li>
<li id="monospace" tabindex="-1">Monospace</li>
<li id="fantasy" tabindex="-1">Fantasy</li>
</ul>
</li>
<li id="mb1_menu2" tabindex="-1">
Style
<ul id="styleMenu" title="Style" tabindex="-1">
<li id="italic" tabindex="-1">Italics</li>
<li id="bold" tabindex="-1">Bold</li>
<li id="underline" tabindex="-1">Underlined</li>
</ul>
</li>
<li id="mb1_menu3" tabindex="-1">
Justification
<ul id="justificationMenu" title="Justification" tabindex="-1">
<li id="left" tabindex="-1">Left</li>
<li id="center" tabindex="-1">Centered</li>
<li id="right" tabindex="-1">Right</li>
<li id="justify" tabindex="-1">Justify</li>
</ul>
</li>
</ul>
停用控制元件
當自定義控制元件變為停用狀態時,透過將 tabindex="-1" 設定為 -1 來將其從 Tab 順序中移除。請注意,分組控制元件(如選單中的選單項)中的停用項應仍可透過箭頭鍵導航。
管理組內焦點
當用戶透過 Tab 鍵離開某個元件並返回時,焦點應返回到之前具有焦點的特定元素,例如樹狀項或網格單元格。有兩種方法可以實現此目的:
- 漫遊 tabindex:以程式設計方式移動焦點
aria-activedescendant:管理“虛擬”焦點
技術 1:漫遊 tabindex
將當前焦點的元素的 tabindex 設定為“0”可確保,如果使用者透過 Tab 鍵離開元件然後返回,組內選定的專案將保留焦點。請注意,將 tabindex 更新為“0”還需要將先前選定的專案更新為 tabindex="-1"。此技術涉及響應按鍵事件以程式設計方式移動焦點,並更新 tabindex 以反映當前具有焦點的專案。為此:
為組中的每個元素繫結一個按鍵處理程式,當使用箭頭鍵移動到另一個元素時:
- 以程式設計方式將焦點應用於新元素,
- 將當前焦點元素的
tabindex更新為“0”,以及 - 將先前焦點元素的
tabindex更新為“-1”。
技術 2:aria-activedescendant
此技術涉及將單個事件處理程式繫結到容器元件,並使用 aria-activedescendant 來跟蹤“虛擬”焦點。(有關 ARIA 的更多資訊,請參閱此 可訪問 Web 應用程式和元件概述。)
aria-activedescendant 屬性標識當前具有虛擬焦點的後代元素的 ID。容器上的事件處理程式必須透過更新 aria-activedescendant 的值來響應按鍵和滑鼠事件,並確保當前專案被適當地設定樣式(例如,透過邊框或背景顏色)。
一般準則
焦點事件的使用
- 請勿分派
focus事件來將焦點發送到某個元素。DOM 焦點事件僅用於資訊:它們在某個元素獲得焦點後由系統生成,但實際上不用於設定焦點。請使用element.focus()代替。 - 請監聽
focus和blur事件來跟蹤焦點變化。不要假設所有焦點變化都來自按鍵和滑鼠事件:輔助技術(如螢幕閱讀器)可以將焦點設定到任何可聚焦的元素。如果您想跟蹤整個文件的焦點狀態,可以使用document.activeElement來獲取活動元素,或者使用document.hasFocus來確保當前文件是否具有焦點。
確保鍵盤和滑鼠產生相同的體驗
為了確保使用者體驗無論輸入裝置如何都保持一致,鍵盤和滑鼠事件處理程式應在適當的地方共享程式碼。例如,當用戶使用箭頭鍵導航時更新 tabindex 或樣式的程式碼也應被滑鼠點選處理程式使用,以產生相同的更改。
確保鍵盤可用於啟用元素
為了確保鍵盤可用於啟用元素,繫結到滑鼠事件的所有處理程式也應繫結到鍵盤事件。例如,為了確保 Enter 鍵可以啟用元素,如果您有一個 onclick="doSomething()",您也應該將 doSomething() 繫結到按鍵事件:onkeydown="event.code === "Enter" && doSomething();"。
始終為 tabindex="-1" 的專案和以程式設計方式獲得焦點的元素繪製焦點
確保獲得焦點的元素具有焦點環。這可以透過 CSS outline 屬性來完成,該屬性不應被無條件設定為 none — 如果您想阻止顯示不必要的焦點環,請使用 :focus-visible 偽類。
阻止使用的按鍵事件執行瀏覽器功能
如果您的元件處理某個按鍵事件,請透過使用事件處理程式的返回值來阻止瀏覽器也處理它(例如,響應箭頭鍵的滾動)。如果您的事件處理程式返回 false,事件將不會傳播到您的處理程式之外。
例如
<span tabindex="-1">…</span>
span.onkeydown = handleKeyDown;
如果 handleKeyDown() 返回 false,事件將被捕獲,阻止瀏覽器根據按鍵執行任何操作。
此時,不要依賴按鍵重複的一致行為
不幸的是,onkeydown 是否重複取決於您執行的瀏覽器和作業系統。