跳到主要內容區
碼農的好工具 ChatGPT 開箱:高效打造無障礙的頁籤(Tabs)功能
開發實作

碼農的好工具 ChatGPT 開箱:高效打造無障礙的頁籤(Tabs)功能

AI 真的懂無障礙嗎?自動生成能做到多完整?開發者該如何善用這項工具?

更新日期:2023/02/19

發布日期:2023/02/19

作者:Woody

最近科技圈內外最火熱的話題莫過於 AI,AI 的發展也正在逐漸改變我們的開發方式,例如之前 GitHub 推出的基於 OpenAI 的 Copilot,可以根據內文在開發過程中提供程式碼建議,達到四成的正確率。

自去年底 ChatGPT 的發表,已引起了眾多人們的關注,大家都在各自的領域中不斷探索可能。作為一個關心 a11y 的碼農,當然就好奇起 ChatGPT 能在無障礙開發上如何應用了!

這篇文章將分享如何利用 ChatGPT 協助我們進行無障礙開發,以模擬開發一個無障礙的頁籤 (Tabs) 為例,讓我們來看看它能不能成功完成任務吧!

開發一個無障礙的頁籤 (Tabs)

我們本篇的情境是以開發一個無障礙的頁籤為例,並參考 W3C 的 ARIA Authoring Practices Guide (APG) 中 Tab 的內容來訂定組成及行為、鍵盤操作和無障礙屬性等等需要實作的功能。

什麼是頁籤:構成及行為

頁籤 (Tabs) 是用於分類和組織內容的一種方式,它在網站上是常見的資訊分類區塊,讓使用者可以方便地選擇感興趣的類別瀏覽。當使用者選擇了一個類別後,就可以在頁籤面板中瀏覽相關的內容。

頁籤組成構造圖解:頁籤由頁籤、頁籤元素列表和頁籤面板組成

頁籤由頁籤元素列表頁籤面板組成,數量相同。頁籤元素可控制顯示哪個頁籤面板,沿著頁籤顯示面板的一側排列,最常見的是置於頁籤面板頂部的設計。同時只有一個頁籤面板的內容會顯示。每個頁籤面板都有一個關聯的頁籤元素,當一個頁籤元素被選中啟用,對應的頁籤面板會顯示,其他頁籤面板則會隱藏。

預計實作頁籤的鍵盤操作

  1. 當焦點進入頁籤元素列表時,將焦點定位於啟用的頁籤元素上。
  2. 在頁籤元素列表時按下「Tab 鍵」,焦點將移至外面的 tab 面板上。
  3. 透過左右方向鍵切換到上一個/下一個頁籤元素。
  4. 如果啟用的頁籤元素為第一個,左方向鍵會返回最後一個啟用的頁籤元素;如果啟用的頁籤元素為最後一個,右方向鍵會回到第一個啟用的頁籤元素。像一個可循環的圓圈。
  5. 切換啟用的頁籤元素時,焦點同時移至該啟用的元素上。

預計實作頁籤的無障礙語意

  1. 頁籤元素列表節點的角色為 tablist
  2. 頁籤元素的節點角色為 tab
  3. 頁籤面板節點的角色為 tabpanel
  4. 每個 tab 角色的節點具有 aria-controls 屬性指向其相關 tabpanel 元素。
  5. 啟用的頁籤元素 aria-selected 狀態為 true;其他頁籤元素 aria-selected 狀態為 false
  6. 每個 tabpanel 角色的節點具有 aria-labelledby 屬性,其值與指向其相關頁籤元素的顯示文字相同。

那麼接著我們就試著運用 ChatGPT 來輔助實作看看吧!

使用 ChatGPT 實作無障礙頁籤

Step 1:產生構成及行為

Me 🧑‍💻💬 :
Write me a script using the following React code and create a tab pattern with 3 tab item/panel using React and Tailwind CSS that is completely 508 compliant and accessible visually and to screen-readers. import React from 'react'

ChatGPT 回應:
This script creates a Tab component that uses React state to keep track of which tab item is currently active. It uses the Tailwind CSS class names for styling, and implements accessibility best practices by using appropriate focus states and keeping the tab labels and content accessible to screen readers._

生成的程式碼:Step 1 程式碼

基本的頁籤元素列表和頁籤面板的結構產生了,點頁籤元素也會顯示對應關聯的頁籤面板 ⋯⋯ 咦?角色沒有設定無障礙角色與狀態呀,沒關係,提示他一下,請 ChatGPT 改善看看!

尚無設定無障礙語意的accessibility tree

程式碼與一般撰寫時無差別

Step 2:加上無障礙語意

Me 🧑‍💻💬 :
But this example didn’t set role=”tabpanel”/”tabitem” in element

ChatGPT 回應:
Here’s an updated version of the script that sets the role attributes as you requested._

生成的程式碼:Step 2 程式碼

This version of the script sets the roleattributes on the appropriate elements to indicate their role as tab items or tab panels, and also sets the aria-selected and tabIndex attributes on the tab items to indicate which tab is selected and to ensure proper keyboard accessibility.

喔喔,頁籤的無障礙語意需求 1~5 和鍵盤操作的 1 加好了。
此外,我只提示了頁籤元素列表和頁籤面板沒加上角色屬性, ChatGPT 補了 aria-controls, aria-selected,role="tab",真不錯。

加上無障礙語意後,ARIA Attributes即有無障礙語意的設定結果

設定無障礙語意的程式碼

Step 3:加上方向鍵操作功能

Me 🧑‍💻💬 :
Add keyboard control for tabitem:

  1. left arrow can change active tabitems to the previous tab
  2. right arrow can change active tabitems to the next tab
  3. up arrow can change active tabitems to the previous tab
  4. down arrow can change active tabitems to the next tab

ChatGPT 回應:
Here’s an updated version of the script that adds keyboard controls to navigate between tab items.

生成的程式碼:Step 3 程式碼

這邊請 ChatGPT 加上方向鍵可以改變啟用的頁籤,鍵盤操作的 3,4 搞定了,而且沒特別提要 4 的循環啟用頁籤元素的功能,但他也有做了,棒棒!

新增handleKeyDown function來達成方向鍵可以改變啟用的頁籤

設定handleKeyDown function來達成方向鍵可以改變啟用的頁籤

Step 4:讓焦點隨啟用的頁籤而變

Me 🧑‍💻💬 :
Add change focus to active tabitem when active tabitem changed

ChatGPT 回應:
Here’s the updated version of the script with the added feature of changing focus to the active tab item when it changes.

生成的程式碼:Step 4 程式碼

看產生的程式 ChatGPT 有理解我們的部份要求,產生了當 click 頁籤元素時,改變焦點的功能,但方向鍵改變啟用頁籤元素時仍無移動焦點,沒關係,觀察一下之後感覺差一步而已,直接換碼農上工惹 🧑‍💻

設定.focus(),當 click 頁籤元素時,改變焦點

Step 5:修改一下程式碼

檢視 Step 4 的程式碼,發現由於 useEffect 的 dependency 是空陣列,也就是只有首次 render 時會執行將焦點移至第一個頁籤的動作。

useEffect(() => {
	const firstTabItem = document.querySelector("[role='tab']");
	firstTabItem.focus();
}, []);

我們修改將 dependency 陣列中放入 activeTab,當 activeTab 有變化就執行 handleClick function。

useEffect(() => {
	if (tabItems.current[0]) {
		handleClick(activeTab);
	}
}, [activeTab]);

將 dependency 陣列中放入 activeTab,當 activeTab 有變化就執行 handleClick function。

程式碼:Step 5 程式碼

稍微再整理一下,就大功告成了!

如圖 A:

  1. 在 TabPanel 的 component 外層 div 加上 tabIndex 完成鍵盤操作 2 的要求。
  2. TabPanel component 新增傳入 label 並在外層 div 用 aria-label 綁定 label。

圖A為程式碼的截圖
圖A

如圖 B:

  1. 使用 for 迴圈整理的更 clean 一些

圖B為程式碼的截圖
圖B

程式碼:step6.jsx

我們也將逐步改善的過程製作成簡單的展示網頁,你可以透過該網頁來了解每個步驟 accessibility 的變化。

心得

從以上的步驟,可以看出要利用 ChatGPT 開發無障礙功能,需要具備無障礙的基礎知識。你必須有足夠的知識來驗證回覆的內容,因為 ChatGPT 是基於大量由人類創造的網路資料進行訓練而成,它的回覆可能很像人類,但有時可能是不準確、不真實或誤導的。

然而,ChatGPT 可以協助生成一些程式碼片段,基於這些片段進行修改,可以大大提高效率。對於像我已經有一段時間沒常寫 React 而語法相對生殊的人來說,透過 ChatGPT 生成的程式碼片段,也可以降低語法錯誤機率,進而更專注於無障礙設計的實踐上。

你也可以試試看 ChatGPT,了解它的優點和限制,恰當的使用它,相信能夠幫助你更高效地完成任務!

本文作者

本文作者

Woody

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