ARIA无障碍最近在用读屏体验财付通页面的时候,发现有很多弹层。由此想到,那些使用屏幕阅读器的视障朋友,是否也有弹层的概念?他们如何感知到在某个操作后,页面弹出了一个对话框?

后来,看到进步博客里《创建无障碍的对话框》的文章。里面提到ARIA role的使用:

将一个元素的role属性设置为dialog,浏览器则会把该元素看作为一个对话框。当role属性值为dialog的元素可见时,浏览器会告知屏幕阅读器一个对话框已打开。这可以让屏幕阅读器用户意识到,他们已经不在页面的常规流中了。

浅识ARIA,把所了解到的跟大家分享一下!

原文地址:http://yaccessibilityblog.com/library/understanding-aria-widgets.html

P.S. 目前国内的读屏软件暂不支持ARIA,可下载国外的NVDA试用。据了解,争渡下个版本也要开始支持了。

再说点废话:开发人员使用HTML、CSS和JavaScript构建交互美观的网页时,往往会忽略视障人士。所以,有时候这些代码无法被读屏软件等辅助技术理解。WAI-ARIA能够提供足够的语义,以确保读屏软件可以完全理解我们的网页,从而告诉视障朋友。举几个例子,大家可能更容易明白:
财付通导航
我们通常使用ul、li来实现导航,正常人一看就知道。那么盲人用户如何知道当前浏览区域就是网站主导航?
默认下拉菜单财付通下拉菜单

对于浏览器默认的下拉组件,读屏软件可以识别并告诉使用者这是“组合框”。而通常情况下,我们为了美观,会使用li来自定义,读屏软件只能识别出这是一个“列表“。这显然对视障用户来说,是不语义的。那如何让盲人用户知道我们使用li标签是用来模拟标准select控件呢?

好了,开始介绍:

ARIA是一个可以用来显著提高自定义组件可访问性的W3C规范。本文通过现有的HTML组件对ARIA进行解释。

为了尽可能的简洁明了,本文只讨论ARIA的标记和样式。

(一)ARIA Roles
ARIA定义了在当前已实现的HTML之外的语义。正如规范所说,它好比一座桥——填补了各个版本HTML规范之间的差异。比如,HTML4和HTML5都没有提供工具栏和对话框组件的语义,但是它们都可以用ARIA来定义。如下面两个例子:
工具栏:
<div id="tb-1" role="toolbar">
    <button type="button">Print</button>
    <button type="button">Move</button>
    <button type="button">Delete</button>
</div>
对话框:
<div role="dialog">...</div>

如例子中所示,使用ARIA只要给现有的html标签添加role属性。我们也可以通过javascript给元素添加role。

// Using native DOM
document.getElementById("tb-1").setAttribute("role", "toolbar");
// Using jQuery
$("#tb-1").attr("role", "toolbar");
// Using YUI
Y.one("#tb-1").set("role", "toolbar");
跟input元素的type属性一样,ARIA role的属性值也只能设为预定义的几个值。基于渐进增加的思想,当构建网页结构时,都是先以最语义化的标签定义,再用ARIA补充。例如下面这个由<ul>构成的树结构:
<ul role="tree" tabindex="0">
    <li role="treeitem" tabindex="-1">Item 1</li>
    <li role="presentation">
        <a href="#group-1" role="treeitem" aria-expanded="true" tabindex="-1">Item 2</a>
        <ul id="group-1" role="group">
            <li role="treeitem" tabindex="-1">Item 2-1</li>
            <li role="treeitem" tabindex="-1">Item 2-2</li>
            <li role="treeitem" tabindex="-1">Item 2-3</li>      
        </ul>
    </li>
</ul>

释:同HTML5中的nav标签代表导航一样,aria中role的定义相当于为代码提供了更多的语义化。role=”toolbar”就代表这里的要表现的是一个工具栏role=”dialog”表示这里表现的是一个对话框。role可以定义的语义还有很多,如:role=”listbox”表示下拉列表框。当你用li模拟select时就可以定义。

(二)ARIA属性

跟现有的HTML标签一样,ARIA也有属性来定义他们的行为。例如,一个<textarea>可以通过添加readonly属性来定义为只读。ARIA属性的方法也一样,不过他们需要加上“aria”前缀。

例如,上面的树状结构可以使用aria-multiselectable属性来支持多种选项。
<ul role="tree" tabindex="0" aria-multiselectable=”true”>...</ul>
ARIA属性也可以在现有的HTML组件上使用。例如,使用aria-haspopup属性定义一个有弹出菜单的按钮。
<button id="btn-1" type="button" aria-haspopup="true">Show Options</button>

我们也可以通过javascript设置属性:

// Using native DOM
document.getElementById("btn-1").setAttribute("aria-haspopup", true);
// Using jQuery
$("#tb-1").attr("aria-haspopup", true);
// Using the set() method of YUI3
Y.one("#tb-1").set("aria-haspopup", true);
(三)ARIA状态
ARIA还有一些用来表示状态的标签属性,他们与现有HTML对象中的状态属性一样。例如,HTML中checkbox被选中的状态是用“checked”来表示的:
<input type="checkbox" checked/>
<script type="text/javascript">
document.getElementById("checkbox-1").onclick = function (e) {
  console.log(e.target.checked);
};
</script>
ARIA状态的工作方式与此完全相同。并且像ARIA属性一样,他们也需要“aria-”前缀。如之前树状结构的例子,树节点有打开和收起的状态,这种状态就可以用“aria-expanded”来表示:
<a href="#group-1" role="treeitem" aria-expanded="true" tabindex="-1">Item 2</a>
<ul id="group-1" role="group">
    <li role="treeitem" tabindex="-1">Item 2-1</li>
    <li role="treeitem" tabindex="-1">Item 2-2</li>
    <li role="treeitem" tabindex="-1">Item 2-3</li>
</ul>
与ARIA属性一样,ARIA状态也可以用在现有的HTML对象上。例如,添加“aria-invalid”标签属性来表示用户在文本框中输入的值无效。
<input type="text" aria-invalid="true">
管理状态和属性
现有HTML对象的状态和属性对应的行为变化是由浏览器完成的。例如,当用户选中或者去除一个选框时,浏览器自动变化它的checked属性值,而不需要再用js去定义。
<input id="checkbox-1" type="checkbox" checked>
与HTML对象不同,ARIA对象的状态和属性对应的行为并不是由浏览器来实现的。因此,我们就有必要使用js来实现预想的行为。再回到前面所说的树结构的例子,叶子节点可能定义了aria-expanded的初始状态,但是此状态在响应了点击事件后会进行切换。
初始状态定义:
<a id="treeitem-1" href="#group-1" role="treeitem" aria-expanded="false">Item 2</a>
使用js进行状态切换:
function onItemClick(e) {
  e.preventDefault();
  var target = e.target;
  target.set("aria-expanded", !(target.get("aria-expanded") === "true"));
}
document.getElementById("treeitem-1").onclick = onItemClick;
(四)ARIA labels

<label>标签一直被用来为现有的HTML对象指定标签。而ARIA提供了一些新的方法。

aria-label属性
为组件指定内置的文本标签,不在视觉上呈现。当屏幕上没有空间再放置一个label时使用非常方便。同时,title属性也可以为视障用户提供一个指引。如下,在表格内的一个多选框:
<input type="checkbox" aria-label="Message 1" title="Click to select this message">
aria-labelledby属性
当想要的标签文本已在其他元素中存在时,可以将其值为该元素的id。例如:
警示对话框:
<div role="alertdialog" aria-labelledby="hd" aria-describedby="msg">
    <form>
    <fieldset>
        <legend id="hd">Confirm Action</legend>
        <p id="msg">Are you sure you want to submit this form?</p>
        <input type="button" id="ok-button" value="OK">
        <input type="button" id="cancel-button" value="Cancel">
    </fieldset>
    </form>
</div>

释:当前对话框要进行一个“确认行为”。当该对话框弹出时,视障用户就可以听到它的主题,即id为“hd”元素里的文本内容。

列表项:
<h2 id="hd">Folders</h2>
<ul role="listbox" aria-labelledby="hd" tabindex="0">
    <li role="option" tabindex="-1">Inbox</li>
    <li role="option" tabindex="-1">Drafts</li>
    <li role="option" tabindex="-1">Sent</li>
</ul>

释:此为使用li模拟的select组件。视障用户tab到时,可以知道当前操作是指定文件夹。

aria-describedby属性
当前的某一元素为某组件的补充说明,可以将组件的该属性值设置为某元素的id。例如,表单中用户输入无效的错误提示。
<label for="first-name">First</label>
<input type="text" name="first-name" id="first-name" required aria-required="true" aria-invalid="true" aria-describedby="err-msg">
<p id="err-msg">Cannot be blank.</p>
(五)ARIA对象的样式
与现有的HTML对象不同,ARIA对象没有的提供默认的样式。然而,大多数现代浏览器已经支持css选择器,这样就很容易可以通过role属性值定义对应ARIA对象的样式。

ul[role=tree] {…}
div[role=dialog] {…}
为指定的状态定义样式
与行为一样,现有的HTML对象的各状态都有浏览器的默认样式。例如,当用户操作了一个多选框,多选框内就会添加或者去掉一个标记。当disabled的属性去除时,浏览器就会自动把灰色的样式去除。
如之前所说,ARIA对象的状态和属性不是由浏览器来实现的。开发者必须对各个状态和属性定义相对应的样式。在大多数的现代浏览器中,这可以通过CSS选择器来完成。

例如,为一个有弹出菜单的按钮定义样式:

button[aria-haspopup] {…}

再回到之前的树结构,为展开和收起状态定义样式:
a[aria-expanded=true] + ul[role=group] {display: block;}

a[aria-expanded=false] + ul[role=group] {display: none;}

(六)Widget Role指南

ARIA role属性只能设置为预定义的值。为了方便开发者方便找到合适的值,ARIA role已分abstract role、widget role和landmark role三类。以下列出widget role值,可链接到ARIA指南里的具体描述。

  • spinbutton  表示可微调,可上下调整数值范围。
  • slider 表示滑动条。
  • progressbar 表示进度条。
  • button 表示按钮。
  • radio 表示单选框,自定义时可使用
  • textbox 表示输入框,自定义时可使用
  • checkbox 表示复选框,自定义时可使用

更多详情请浏览《ARIA指南》

通过使用ARIA roles及其相关属性,我们可以解决开头提到的问题:

(1)    盲人用户如何知道当前浏览区域就是网站主导航?

<div id="mainnav" role="navigation">
    <a href="http://news.qq.com/" target="_blank">新闻</a>
    <a href="http://v.qq.com/" target="_blank">视频</a>
    <a href="http://ent.qq.com/" target="_blank">娱乐</a>
</div>

(2)    如何让盲人用户知道我们使用li标签是用来模拟标准select控件?

<div class="dropdown">
    <a href="javascript:;"  role="combobox" aria-autocomplete="list" aria-owns="question-list"  aria-expanded="true">选择提示问题</a>
    <ul id="question-list" role="listbox">
        <li role="option"><a href="javascript:;">我妈妈的名字是?</a></li>
        <li role="option"><a href="javascript:;">我爸爸的名字是?</a></li>
        <li role="option"><a href="javascript:;">我爱人的名字是?</a></li>
    </ul>
</div>