Accessibility開發與實踐系列

巧用 tabindex 讓你的 UI 更鍵盤友善

tabindex 在開發上該怎麼使用?何時使用它?

A11y新手村🏕
a11yvillage

--

裝飾型封面圖片

這篇文章我們將介紹控制焦點的屬性 tabindex 在開發上該怎麼使用?何時使用它?怎麼使用是好的用法,怎麼使用會對 accessibility 有負面的影響?相信看完後你會對 tabindex 有更深的認識,留意在開發中使用它時應該注意的細節。

現今從網路上我們不僅能獲得資訊與知識,透過網路完成日常作業也隨處可見,想像你今天打開瀏覽器上網,一定不會只是單純瀏覽一個靜態網頁看看文字圖片。我們現在有許多線上的產品與服務,例如google文件或是網路銀行,其實都是要一邊操作網頁一邊完成任務。

只要是需要讓使用者操作的環節,像是用按鈕來送出動作或表單元素的填寫,好的焦點移動項目與順序可以讓使用者快速完成任務,而因為焦點是鍵盤使用者的定錨器,不恰當的運用屬性設定不但會降低效率,甚至導致使用者對頁面操作的認知困惑。你可曾遇過頁面捲了很久還是沒發現提示訊息,仔細尋找才發現在一個不顯眼的角落嗎?這樣的情境只要開發時一不小心,類似不好的 UX 在螢幕閱讀器操作中可說是隨處可見。

物件的聚焦狀態

畫面上我們看到的各式元素中都隱藏著一個用來描述它是否可聚焦的屬性 isFocusable,其值如果是 true 時表示我們可透過鍵盤的 tab 鍵聚焦到這個元素上,常見預設為可聚焦的元素如按鈕、連結、表單控制元件(輸入框、下拉式方塊)等;反之其值如果是 false 則表示無法透過鍵盤的 tab鍵聚焦,常見的預設不可聚焦元素如圖片、文字和標題等這類呈現資訊內容的元素。

在應用程式型的頁面中,常會有許多需要使用者互動的元素。焦點是讓使用者能夠透過鍵盤選擇並互動的關鍵。而有時,我們會需要修改元素是否可以聚焦的狀態,在 HTML 中,透過 tabindex 屬性可以實現這一點。例如,將 tabindex 設置為 0 可以讓本來不可獲取焦點的元素變為可聚焦元素;而設置 tabindex 為 -1 則可以讓原本可透過鍵盤 Tab 鍵能聚焦的元素改為僅能透過呼叫元素的 focus 方法來獲得焦點。這種機制讓開發者可以更精細地控制頁面上元素的焦點行為和順序,以提升使用者的互動體驗。

Demo 原生按鈕與非原生按鈕差異:

使用 <div> 製作按鈕時,因 <div> 只是一個區塊標籤,預設是無法聚焦的,我們此時就必需加上 tabindex=”0" 來讓其可聚焦,而在原生的 <button> 上就不需要加上此 tabindex=”0" 的屬性。

HTML 中元素的 tabindex 屬性

在 HTML 中,`tabindex 屬性用於指定元素是否能夠透過鍵盤 tab 鍵獲得焦點,以及其在 tab 鍵導航中的順序。當 tabindex 的值設置為大於等於 0 時,該元素可透過鍵盤的 tab 鍵被聚焦。設置為 -1 時,該元素不可透過 Tab 鍵導航,但可以透過 JavaScript 的 focus() 方法來聚焦。我們應只使用 tabindex 為 0 或 -1。

  • tabindex=”0" 使元素可聚焦,且使用 Tab 鍵跳轉時,跳轉順序會按照 DOM 的排列順序進行導航
  • tabindex=”-1" 僅允許透過 JavaScript 呼叫元素的 focus 方法來聚焦到元素上,而不能使用鍵盤 tab 鍵來聚焦
  • tabindex=”1"(或任何大於 1 的數值)允許元素透過鍵盤 tab 鍵獲得焦點,並可以自定其在 tab 導航中的移動順序。然而,使用大於 1 的值是一種 anti-pattern 我們應該避免這樣做。

Demo:

  • 使用 tabindex 大於 0 的值可以自訂 tab 鍵導航順序,上例中的導航順序是 1 → 2 → 3 → 4 ,但 DOM 的順序是 1 → 2 → 4 → 3
  • 使用 tabindex 等於-1 時,僅能透過元素的 focus 方法聚焦,上例中按鈕 5 僅能透過按下按鈕 6 來聚焦

tabindex 不好的使用方式

使用大於 0 的 tabindex 值來設定焦點導航順序

設定 tabindex 值大於 0 的元素會比未設定 tabindex 或設定為 “0” 的元素優先獲得焦點,這樣會導致使用鍵盤 Tab 鍵進行導航的順序與螢幕閱讀器的導航順序不一致,進而讓螢幕閱讀器的使用者難以建立心理地圖。

焦點在 1~8 各個按鈕間移動的動畫圖

螢幕閱讀器會依據 DOM 結構生成內部的資料結構,其中物件的排列順序會與 DOM 中元素的排列順序相同,並依此順序進行導航。為了確保 Tab 鍵導航與螢幕閱讀器導航的一致性,我們應避免使用 tabindex 值大於 0 的設定,而是將它們按邏輯順序適當地排列在 DOM 中。如果需要基於視覺考量調整元素位置,應使用 CSS 變更其視覺位置,這樣既不會影響 DOM 結構,也能保持符合邏輯的焦點導航順序。

鍵盤 tab 導覽順序與螢幕閱讀器導覽順序可能會不同
  • 螢幕閱讀器導覽順序仍依照 DOM 元素順序導覽(5 → 6 → 1 → 2 → 4 → 3 → 7 → 8)
  • tab 導覽順序則會依據 tabindex 設定的值由小而大導覽,接著才導覽無 tabindex 值的元素(1 → 2 → 3 → 4 → 6 → 7 → 8)

螢幕閱讀器使用者通常會穿插的使用 tab 導覽/螢幕閱讀器導覽頁面,當 tab 導覽與螢幕閱讀器導覽不一致時,便很容易忽略掉某些元素。例如以下操作就會漏掉 1~4 按鈕的導覽:

  1. 上下鍵導覽會先到 5, 6 按鈕(螢幕閱讀器導覽依 DOM 順序)
  2. 2. tab 鍵導覽時會往下到可聚焦物件 7, 8 按鈕(tab 導覽會略過 1~4 的按鈕)

不一致的 DOM 順序與視覺排列順序

除非有特殊需求,不然 DOM 的排列順序與視覺呈現應盡量保持一致。

使用 css 的 float: right 將編號 2 按鈕移到右側,使 tab 導覽順序與視覺順序不同

上面的例子中我們使用了 `float: right` 將按鈕 2 移到右側,但在 DOM 中,它的順序仍位於按鈕 1 與按鈕 3 之間,更好的做法是調整按鈕 2 在 DOM 中的位置,將其移至按鈕 4 之後。這樣的安排使得視覺與 DOM 結構順序一致,有助於維持良好的無障礙導航體驗。

利用 tabindex=”0" 使非互動元素可以聚焦

你是否想過將 tabindex=”0" 設定在非互動的元素(如段落、標題、列表等)上,讓螢幕閱讀器使用者透過鍵盤 Tab 鍵就可以瀏覽所有內容,來提高無障礙體驗?但這樣的做法事實上並沒有提供更好的無障礙體驗,因為螢幕閱讀器是有其專屬的操作方式來瀏覽這些非互動內容。

相反地,將 tabindex 屬性加到非互動元素上,反而可能產生一些無障礙問題:

  • 對於使用螢幕閱讀器進行操作的使用者,這樣的做法反而增加了區分可互動元素和非互動元素的難度
  • 僅使用鍵盤導航的使用者(例如運動障礙者)需要按更多次鍵盤 Tab 鍵才能到達他們想要互動的元素上,反而增加了操作的不便

tabindex 好的運用方式

運用在互動小部件上

tabindex=”-1" 可運用在內部管理焦點的互動小部件上(例如 gridmenu),這些小部件是由多個可聚焦元素所組成,同時間只會有一個元素是 active 狀態,其餘的元素皆會是 inactive 狀態,而小部件內部通常使用鍵盤方向鍵來切換 active 元素,實做上會將 active 元素的 tabindex 設為 0 而將 inactive 元素的 tabindex 設為 -1 再搭配 JavaScript DOM 物件的 focus() 方法來改變焦點。

Demo 索引標籤小部件:

Demo 的索引標籤小部件可使用 tab 鍵跳至切換分頁的頁籤上並使用方向箭來改變 active 的頁籤。

可滾動的 overflow 容器

tabindex=”0" 應該用於任何帶有 CSS overflow 屬性的容器上。這樣做的目地是讓鍵盤使用者可透過 tab 鍵將焦點移至該容器上同時使用方向鍵來控制捲軸的滾動,以便查看容器內完整的內容。

此外可以在該容器上提供描述文字,讓螢幕閱讀器使用者當聚焦到容器時就能得知這個容器的用途。有以下這些做法:

  • 使用 aria-label 或 aria-labelledby 描述放置在容器中的內容
  • 使用 HTML 語意元素或 role=”group” 等方式將容器加上地標語意

Demo:

客製元素

當沒有適當的 HTML 元素的互動小部件需要使用 <div>/<span> 客制時,這些非原生可互動元素需要加上 tabindex=”0"來讓 tab 鍵盤焦點可聚焦。

這邊有個例子Listboxes,它是一個列表容器與一個顯示選項列表並可以選擇其中一個選項的小部件,可看到其中的列錶容器 <ul> 上使用了 tabindex=”0" 來讓小部件可以被聚焦。

這篇文章中我們介紹了 tabindex 好的與不好的用法,像是使用者通常會透過視覺/螢幕閱讀器/tab 等不同方式來導覽整個介面,各種瀏覽導覽方式的順序一致性很重要,可避免使用者不小心略過重要的內容。未來再遇到這些情境時,別忘了正確的使用 tabindex,讓你的介面與內容都能讓鍵盤與螢幕閱讀器使用者無障礙的使用喔!

本文作者:Woody

熱愛學習與開發程式的軟體工程師,對知識充滿好奇心,喜歡與人的互相分享。歡迎來一起協作開發各種 accessibility 專案。

--

--

A11y新手村🏕
a11yvillage

每週分享Accessibility相關原創文章,實用性內容包含原理,UX/UI設計到開發實作等,也會訪問障礙者與正在Accessibility實踐路上耕耘的人,邀請你入村跟我們一起創造包容友善的世界🏕