支援鍵盤導航的 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 元素已經可以透過鍵盤訪問,因此使用其中一個是最快的使元件能夠與鍵盤協同工作的方法。

作者還可以透過新增 tabindex0 來使 <div><span> 可透過鍵盤訪問。這對於使用 HTML 中不存在的互動式元素的元件特別有用。

分組控制元件

對於選單、選項卡列表、網格或樹形檢視等分組元件,父元素應位於 Tab 順序中(tabindex="0"),並且每個子元素選擇/選項卡/單元格/行應從 Tab 順序中移除(tabindex="-1")。使用者應該能夠使用箭頭鍵導航子元素。(有關通常預期用於典型元件的鍵盤支援的完整描述,請參閱 WAI-ARIA 創作實踐)。

下面的示例展示了這種技術如何與巢狀選單控制元件一起使用。一旦鍵盤焦點落在包含 <ul> 元素上,JavaScript 開發人員必須以程式設計方式管理焦點並響應箭頭鍵。有關在元件內管理焦點的技術,請參閱下面的“管理組內的焦點”。

html
<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" 將其從 Tab 順序中移除。請注意,分組元件中的停用項(例如選單中的選單項)應能夠繼續使用箭頭鍵進行導航。

管理組內的焦點

當用戶從元件切換到其他位置再返回時,焦點應返回到具有焦點的特定元素,例如樹項或網格單元格。有兩種技術可以實現這一點

  1. 遊動 tabindex:以程式設計方式移動焦點
  2. aria-activedescendant:管理“虛擬”焦點

技術 1:遊動 tabindex

將聚焦元素的 tabindex 設定為“0”可確保如果使用者從元件切換到其他位置再返回,組內的選中項將保留焦點。請注意,將 tabindex 更新為“0”也需要將先前選中的項更新為 tabindex="-1"。此技術涉及以程式設計方式響應按鍵事件移動焦點並更新 tabindex 以反映當前聚焦的項。為此

為組中的每個元素繫結一個鍵盤按下處理程式,當使用箭頭鍵移動到另一個元素時

  1. 以程式設計方式將焦點應用於新元素,
  2. 將聚焦元素的tabindex更新為“0”,以及
  3. 將先前聚焦元素的tabindex更新為“-1”。

這是一個使用此技術的WAI-ARIA 樹檢視示例。

提示

使用element.focus()設定焦點

不要使用createEvent()initEvent()dispatchEvent()將焦點發送到元素。DOM 焦點事件僅被視為資訊性事件:在某個元素獲得焦點後由系統生成,但實際上不用於設定焦點。請改用element.focus()

使用onfocus跟蹤當前焦點

不要假設所有焦點更改都來自鍵盤和滑鼠事件:螢幕閱讀器等輔助技術可以將焦點設定為任何可聚焦元素。請改用onfocusonblur跟蹤焦點。

onfocusonblur現在可以與每個元素一起使用。沒有標準的DOM介面來獲取當前文件焦點。如果要跟蹤焦點狀態,可以使用document.activeElement獲取活動元素。您還可以使用document.hasFocus來確保當前文件焦點。

技術 2:aria-activedescendant

此技術涉及將單個事件處理程式繫結到容器小部件,並使用aria-activedescendant跟蹤“虛擬”焦點。(有關 ARIA 的更多資訊,請參閱此可訪問 Web 應用程式和小部件概述。)

aria-activedescendant屬性標識當前具有虛擬焦點的後代元素的 ID。容器上的事件處理程式必須響應鍵和滑鼠事件,方法是更新aria-activedescendant的值並確保當前專案以適當的方式設定樣式(例如,使用邊框或背景顏色)。

通用指南

使用onkeydown捕獲鍵盤事件,而不是onkeypress

IE 不會為非字母數字鍵觸發keypress事件。請改用onkeydown

確保鍵盤和滑鼠產生相同的體驗

為了確保使用者體驗在任何輸入裝置下都保持一致,鍵盤和滑鼠事件處理程式應在適當的情況下共享程式碼。例如,當用戶使用箭頭鍵導航時更新tabindex或樣式的程式碼也應由滑鼠單擊處理程式使用以產生相同的更改。

確保可以使用鍵盤啟用元素

為了確保可以使用鍵盤啟用元素,繫結到滑鼠事件的任何處理程式也應繫結到鍵盤事件。例如,為了確保 Enter 鍵可以啟用元素,如果您有onclick="doSomething()",則還應將doSomething()繫結到鍵盤按下事件:onkeydown="event.code === "Enter" && doSomething();"

始終為tabindex="-1"的專案和以程式設計方式接收焦點的元素繪製焦點

IE 不會自動為以程式設計方式接收焦點的專案繪製焦點輪廓。在更改背景顏色(例如this.style.backgroundColor = "gray";)或新增點狀邊框(例如this.style.border = "1px dotted invert")之間進行選擇。在點狀邊框的情況下,您需要確保這些元素最初具有不可見的 1px 邊框,以便在應用邊框樣式時元素不會增長(邊框佔用空間,而 IE 沒有實現 CSS 輪廓)。

防止使用的鍵盤事件執行瀏覽器功能

如果您的視窗小部件處理鍵盤事件,請使用事件處理程式的返回值阻止瀏覽器也處理它(例如,響應箭頭鍵滾動)。如果您的事件處理程式返回false,則該事件將不會傳播到您的處理程式之外。

例如

html
<span tabindex="-1" onkeydown="return handleKeyDown();"></span>

如果handleKeyDown()返回false,則該事件將被消耗,阻止瀏覽器根據按鍵執行任何操作。

目前不要依賴於按鍵重複的一致行為

不幸的是,onkeydown可能會或可能不會重複,具體取決於您正在執行的瀏覽器和作業系統。