70

Element 中的 AT 可访问性

 6 years ago
source link: https://zhuanlan.zhihu.com/p/31117272?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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);
}

使用 AT 设备如 Voiceover 或 Chrome 插件 ChromeVox 来测试可访问效果;

注意:因每个 UA 和 AT 对 ARIA 和 Accessibility APIs 的支持情况不一样,因此不同的 UA & AT 组合使用的效果会有略微差异;


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK