在上篇中我們介紹了 Live Regions 的基本概念,包括其使用情境、ARIA 屬性,以及常見的 Alert Pattern。然而,在實際開發過程中,事情可能不會這麼單純。由於不同瀏覽器和螢幕閱讀器對於無障礙功能實作上的差異,我們傳達重要資訊的目標可能無法如預期般達成。開發時我們可以注意一些實作上的細節來減少這類非預期行為的發生機會。
在實作篇中,我們將探討在開發 Live Regions 時常見的錯誤和陷阱,以及哪些情境不宜使用 Live Regions,並介紹一些常用的套件。這些知識將幫助你開發出更具可訪問性的動態網頁。
- 搜尋功能:在搜尋編輯框輸入文字的過程中,經常可以看到有提供輸入提示建議的功能。對視覺操作使用者來說,每輸入一個字,便可以看到對應的建議項目,這樣即時的搜尋建議回饋是非常直覺便利的。然而,對螢幕閱讀器的使用者而言,他們必需在輸入框和建議列表之間來回切換才能得知是否有新的建議項目。此時,我們應該要使用 Live Regions 來通知使用者建議列表已更新。此外,在顯示搜尋結果列表時,也應該使用 Live Regions ,但考慮到搜尋結果通常較多,我們不宜將所有內容都放進 Live Regions 中,而是提供一個簡短的摘要,像是「找到 n 個結果」,來告知使用者。
- 表單驗證:若是輸入時即時回饋的錯誤 (inline errors),建議使用
aria-live="polite",而在表單提交之後出現的錯誤則使用aria-live="assertive",並搭配適當的焦點控制來告知使用者錯誤的欄位。 - 輪播 (Carousel):自動輪播圖片時「不要」使用
aria-live="polite"/"assertive",這是因為自動輪播圖片屬於應用程式自主產生的動態內容變化,如果使用了aria-live="polite"/"assertive"將會讓螢幕閱讀器使用者在閱讀頁面其他內容時不斷被自動產生的 Live Regions 訊息所干擾。此外,在 APG 中對輪播的要求之一,是當鍵盤焦點在輪播區塊時應停止輪播,並設定aria-live="polite"讓使用者在手動切換輪播畫面時,螢幕閱讀器可以得知切換後當前顯示的畫面資訊。(關於輪播的無障礙設計是一個複雜的主題,我們會在之後專門寫一篇文章來討論。) - 即時聊天:可使用
role="log"達到 Live Regions 的效果。具有role="log"的元素自動帶有aria-live="polite"和aria-atomic="false"屬性。
- 確保在添加訊息節點之前,DOM 中已存在 Live Region 節點
有時候,我們會遇到只需要向螢幕閱讀器使用者提示動態內容變化的情況,而不需要在頁面上以文字方式告知視覺操作使用者。例如,當加入購物車時,通常會有明顯的視覺效果或動畫提示,但對螢幕閱讀器使用者來說可能難以察覺。在這種情況下,實作時通常會使用一個視覺上不可見的 “Live Region” 區域,並使用 JavaScript 來修改該區域的內容,向螢幕閱讀器使用者提供提示訊息。
但需要留意的是,如果我們將外層的 Live Region 節點和內層的訊息節點「同時」添加到 DOM 中,在大多數瀏覽器和螢幕閱讀器的組合下,是無法正確報讀訊息節點內容的。
正確的做法是,我們應該確保首先在 DOM 中添加外層的 Live Region 節點,然後再將內層訊息節點添加為其子節點。換句話說,必須確保在添加訊息節點之前,DOM 中已經存在 Live Region 節點。這種做法才是大多數瀏覽器和螢幕閱讀器組合所支援的,可以最大程度地確保訊息能夠被螢幕閱讀器正確報讀。
- 善用
setTimeout(0)控制 Live Region 的內容變化時間點
若同時(同個 Render Cycle 內)有多個 Live Regions 都發生內容變化(例如同時間有多個表單的欄位都出現錯誤的訊息),我們很難控制螢幕閱讀器的報讀順序,這些報讀順序通常與瀏覽器的無障礙實作方式有關,此種情況下,建議可以試著用 setTimeout(0),來試著控制不同 Live Region 內容變化的時間點。
- **僅在「必要時」使用
aria-live="assertive"**
正如我們在上一篇所提到的那樣,aria-live=”assertive” 會中斷螢幕閱讀器正在進行的讀顯任務,立即刷新新的動態內容來通知使用者。因此,只有在絕對需要立即通知變化時,才應該使用 “assertive” 。在大多數情況下,“polite” 就足夠了。
aria-atomic的節點必須是分開的多個子節點
使用 aria-atomic 屬性時,該元素結構必需由多個子節點組成 (例如包含兩個獨立的 <div>),才會發揮該屬性的作用。以此範例來看,會動態變化的區塊是一個獨立的 <span> 元素,此時,在其父元素設定 aria-atomic 能調整螢幕閱讀器是否閱讀整個父元素底下的內容,或是只有該獨立 <span> 元素內的內容。
在一些情境下,我們可能直覺會想要利用 Live Regions 來告知使用者目前的動態內容變化,但其實並不需要多此一舉。
- 脈絡改變 (Context Changes)
當對話框出現或在單頁應用程式(SPA)中切換頁面時,我們或許希望通知螢幕閱讀器使用者發生了動態內容的改變。然而,這些動態內容的改變通常會伴隨著焦點的轉移,而這樣的焦點變化已經足以讓螢幕閱讀器使用者知道進入了新的脈絡。因此,我們無需依賴 Live Regions 來額外通知使用者。
- 狀態的改變 (State Changes)
對於收合式面板/手風琴 (Accordions)、開關按鈕 (Toggle/Switch) 或是核取方塊 (Checkboxes) 這類具有狀態的元件,當元件的狀態發生變化時,我們無需依賴 Live Regions 來通知使用者該元件狀態的變化。這是因為這些元件的狀態改變是由使用者觸發的,也就是使用者點擊了元件後使狀態發生變化。此時,焦點通常會停留在點擊的元件上,螢幕閱讀器會自動報讀焦點物件上的變化,因此不需要額外的通知。
如果需要的元件並沒有對應的原生元素的話,而需要用手刻的方式來製作時,則可以使用 ARIA states attributes (例如 aria-expanded、aria-checked 等等) 來補充語意。
**React Spectrum Live Announcer**
Adobe 實作自家 React Spectrum 設計系統元件庫時,因為自己的需求而開發的內部套件,這個套件的功能即是前述提到的僅需要向螢幕閱讀器發送報讀、但是視覺上沒有對應顯示文字訊息的情境。不過,也因是內部套件,所以 Live Announcer 是沒有文件的,但 Adobe 仍然有將此套件發佈到 NPM 上供大家使用。
雖然並沒有提供文件,但這個套件的內容並不會很複雜,主要開放了 announce、clearAnnouncer 和 destroyAnnouncer 三個函式讓我們在應用程式中使用,也提供了相關參數讓我們根據需求做調整。最後值得特別提的一點是,雖然這個套件因為是掛在 @react-aria 底下,所以套件名稱帶有 React 的字樣,但其實內部實作是完全使用 Vanilla JavaScript 來操作 DOM 的,這意味著這個套件實際上可以用於任何前端框架,例如 Vue、Nuxt、Svelte 等。
**Radix UI — Toast Component**
與之前有介紹過的 Headless UI 類似,Radix UI 元件庫提供的是一套沒有預設樣式的原始元件 (primitives),並標榜完全符合 WAI-ARIA 的無障礙規範和建議。雖然官方元件庫目前只能在 React 中使用,但網路上也有非官方的 Vue 版本。
Radix UI 的 Toast 元件提供了不少方便的無障礙功能,像是會自動關閉、可以設定熱鍵來快速導引到通知區塊、可以用專屬的 type 來設定 aria-live 的報讀時機 (type=”foreground” or “background”)、可以設定 Action 區塊的替代文字為螢幕閱讀器使用者提供額外資訊等等。
在本篇文章中,我們深入探討了實作 Live Region 時需注意的要點,以及相關的程式套件。讀完這系列文章後,別忘了在未來設計開發表單驗證、購物車變更、即時聊天、搜尋以及輪播等功能時,適當的使用 Live Region ,讓螢幕閱讀器使用者不會漏接重要的資訊。
參考資料






