Element 中的 AT 可訪問性

定義:AT是什麼?

AT 是 Assistive Technologies 的簡寫,是指具有以下特徵的硬體或者軟體:

  • 依賴 UA(User Agent,下文簡稱」UA「) 提供的服務來提取和呈現頁面內容
  • 通過 API 和 UA 進行交互
  • 提供了一系列服務來方便殘障用戶和網站內容進行交互

其中包括:屏幕放大器、屏幕閱讀器、文語轉換軟體、語音識別軟體、輸入替代設備、滑鼠替代設備等;

主要技術:ARIA

可訪問的頁面內容是指頁面結構、頁面組件和行為具有語義化,使得 AT 設備能正確理解和傳達頁面內容給殘障用戶,ARIA 是 Accessible Rich Internet Applications 的簡稱,是 W3C 推出的,用來協助和增強 Internet Applications 的可訪問性,提高與 AT 的互操作性的規範。ARIA 提供了一組特殊的易用性屬性,其中包括 roles, states 和 properties,可以添加到任意標籤上,尤其適用於 HTML5。

一、roles:

描述組件的類型和頁面組織架構。正確定義 role 信息可以讓 AT 知道該如何操作該標籤,一般在用戶的交互過程中,role 值是不會改變的。如果要改變 role 值,需刪除當前元素及其子元素,用帶有 role 值的其他元素來替代它。使用方法如下:

<div role=「button」>按鈕</div> 語義上等同於 <button>按鈕</button>

開發過程中常用的 role 值主要分為以下幾類:

Landmark Roles:

包括 main、banner、main、search、navigation 等,用來劃分頁面結構,AT 設備通過鍵可在各頁面模塊之間進行快捷訪問和操作。

Widget Roles:

包括 tree、menu、dialog、slider,switch 等,也是 Element 組件庫開發中常用到的值,用來描述交互性的 UI 組件的類型。每個 role 值有對應的 states & properties,role 類型之間的存在屬性繼承和嵌套關係,類似於 HTML5 中 ul,li 之間的關係,role="treeitem" 的元素需包含在 role="tree" 的元素中,這個包含可以是通過關係型的 states & properties 進行關聯,也可以是 DOM 結構上的嵌套。

Document Structure:

包括 img、table、list、heading 等,用來描述無用戶交互的靜態內容;

Live Region Roles:

包括 alert、log、marquee、timer 等,用來描述頁面上動態內容區域;

Window Roles:

包括 alertdialog、dialog;用來描述頁面上的窗口組件;

二、states & properties:

描述組件的當前狀態。states 與 properties 略有差異,一般 states 的值在用戶交互過程中會發生變化,如 aria-checked;properties 的值一般是不變的,如 aria-label,但也有一些properties 如 aria-valuenow 會在用戶交互過程中發生改變。 states & properties 一般和 role 屬性配合使用,AT 可以通過訪問 UA 暴露出來的 DOM 信息或者 accessibility API 的映射信息來讀取組件或區域當前的狀態。當 states & properties 的值在用戶交互過程中發生改變時, accessibility API 通過 Event 通知 AT 設備。使用方法如下:

<div role=「button」 aria-label="點擊有彈窗" aria-haspopup="dialog">按鈕</div>

開發過程中常用的 states & properties 主要分為以下幾類:

Widget Attributes:

包括 aria-haspopup、aria-disabled、aria-checked、aria-selected、aria-valuemin 等;一般和 Widget Roles 配合使用。

Live Region Attributes:

包括 aria-busy、aria-live、aria-relevant、aria-atomic;一般用在動態內容區域上,如

<div aria-busy="true">loading...</div>

表示內容正在載入或更新中,AT 需等待內容更新完畢才展示給用戶;

Relationship Attributes:

包括 aria-activedescendant、aria-controls、aria-labelledby、aria-posinset、aria-errormessage 等;用來連接在 DOM 結構上不能直接看出來關係的元素。

以 Element 中 Tabs 組件為例:

<div role="tablist"> <div id="tab-first" aria-controls="pane-first" role="tab" tabindex="-1">用戶管理</div> <div id="tab-second" aria-controls="pane-second" role="tab" aria-selected="true" tabindex="0">配置管理</div> <div id="tab-third" aria-controls="pane-third" role="tab" tabindex="-1">角色管理</div> <div id="tab-fourth" aria-controls="pane-fourth" role="tab" tabindex="-1">定時任務補償</div></div><div class="el-tabs__content"> <div role="tabpanel" id="pane-first" aria-labelledby="tab-first" aria-hidden="true">用戶管理</div> <div role="tabpanel" id="pane-second" aria-labelledby="tab-second">配置管理</div> <div role="tabpanel" id="pane-third" aria-labelledby="tab-third" aria-hidden="true">角色管理</div> <div role="tabpanel" id="pane-fourth" aria-labelledby="tab-fourth" aria-hidden="true">定時任務補償</div></div>

aria-selected=true 表示當前 tab 已被選擇,tab 與 tabpanel 元素在 DOM 樹上不存在包含關係,通過 aria-controls 進行連接;

ARIA & Host Languages

ARIA 的存在是為了增強 Host Languages(HTML5 or SVG)語義信息,並非替代;

當 Host Languages 的原生標籤&屬性能滿足語義化需求時,推薦使用原生的。當沒有原生標籤&屬性能描述 UI 組件的語義時如開發者使用 div+css+js 構造的 Tree 組件,使用 ARIA進行語義補充;

當標籤的原生語義和 ARIA 同時存在一個元素上時,ARIA 具有更高的優先順序;也就是說

<a role="button" /> // 會被解讀為按鈕而不是一個鏈接;

開發者實踐總是快於 ARIA 和 Host Languages 標準的發展,隨著新的 UI 組件的推廣和使用, ARIA 和 Host Languages 也會不斷的有新的語義化標籤和屬性出來支持開發者。

UA & AT & Accessibility APIs

每個系統都有一套底層的 Accessibility APIs 用於向 AT 設備傳遞系統自帶 GUI 的可訪問性信息和交互事件;各 UA 和 AT 設備在不同程度上實現對 Accessibility APIs 的支持,兩者通過系統底層的 Accessibility API 進行信息交互; UA 將 DOM 中的可訪問信息映射到底層 Accessibility APIs 中,AT設備通過訪問底層的 Accessibility APIs 來獲取信息,但也有極少 AT 設備是直接通過訪問 DOM 結構來獲取頁面可訪問信息。當用戶通過 AT 設備進行操作時可以修改 Accessibility APIs 中 states or properties 的值,UA 監聽到變化改變 web 應用的狀態;圖解如下:

實現步驟:

我們以 Element 中的 InputNumber 組件為例,來詳細講解下實現步驟:

1、role & states & properties

  • 首先為組件根元素添加 role="spinbutton" 屬性;
  • 添加必填屬性 aria-valuenow,如果有最大/小值,添加 aria-valuemin、aria-valuemax屬性,aria-valuenow 默認為 0,aria-valuemin、aria-valuemax 默認為無限制;
  • 添加選填屬性 aria-labelledby、aria-describedby、aria-disabled 等屬性;

mounted() { const innerInput = this.$refs.input.$refs.input; innerInput.setAttribute("role", "spinbutton"); innerInput.setAttribute("aria-valuenow", this.currentValue); innerInput.setAttribute("aria-disabled", this.disabled); if (this.max !== Infinity) { innerInput.setAttribute("aria-valuemax", this.max); } if (this.min !== -Infinity) { innerInput.setAttribute("aria-valuemin", this.min); }}

2、 更新 states & props

當用戶交互過程中,組件狀態發生變化時,通過js腳本更新相關屬性值 aria-valuenow

updated() { const innerInput = this.$refs.input.$refs.input; innerInput.setAttribute("aria-valuenow", this.currentValue);}

3、測試

使用 AT 設備如 Voiceover 或 Chrome 插件 ChromeVox 來測試可訪問效果;

注意:因每個 UA 和 AT 對 ARIA 和 Accessibility APIs 的支持情況不一樣,因此不同的 UA & AT 組合使用的效果會有略微差異;

推薦閱讀:

當我們在談論前端加密時,我們在談些什麼
極樂技術周報(第二十期)
開發者和用戶之間的世界觀距離有多大?
前端系列教學(入門篇) - 響應式設計(2)

TAG:Accessibility | 前端开发 |