开发和测试访问无障碍的Web应用

Accessibility简称A11Y,指的是软件产品的可访问性,易用性。A11Y 的出发点是让所有的群体所有的人都可以访问 Web 或者软件应用,本文主要关注 Web 应用的可访问性,主要针对访问 Web 应用有障碍的人士,下面针对几类主要人群对 Web 应用提出的挑战以及我们开发时应该解决得问题加以介绍:

视力有障碍的人士,无法像正常人一样用眼睛浏览网页。此时的解决办法就是用读屏软件将网页上的内容转成声音以帮助用户了解屏幕的内容。对于听力和视力均有障碍的人还可以将网页内容转成盲文使其变得可读。由此带来的需要我们开发人员提供的就包括:鼠标变得毫无用处,因此必须提供键盘支持;对于图片必须提供文字的描述信息;方便的链接指导用户到自己需要了解的内容;颜色变得不可识别,因此仅仅靠颜色识别的信息变得不可识别。为使当前网站上越来越多的音频和视频内容被听力有障碍的人士所理解,就需要提供字幕。

如何使得一个 Web 应用变得更加易用,使得残障人士都能无障碍访问呢?首先需要有一个标准,Web 开发者遵循这个标准开发 Web 应用,浏览器可以识别这些为可访问性使用的元素,而辅助科技(Assistive) 可访问发起组织(WAI)是 W3C 的一部分,主要负责可访问标准,准则的制定,而 Web 内容可访问指南(WCAG)是 WAI 制定的一系列文档。目前的版本是 2.0。WAI-ARIA(WAI- 可访问的富客户端应用)则是 WAI 针对 Web2.0 的富客户端应用提出的一个新的指南,定义了一系列的 role(角色)和 property(属性),使得动态的 Web 应用以及 Ajax 的应用能够更加容易得为残障人士无障碍得访问。

常用工具简介

Webking 是 Parasoft 公司开发的一款自动化测试工具,可以使用其进行白盒、黑盒和回归测试。本文主要关注该工具在 A11y 方面所做的检查与测试。Webking 所遵循的是 CI162 所规定的检查列表。Webking 解决得问题就是把不符合 CI162 标准的元素找出来,分析报告包括以下几类,V:违例; SV:严重违例; PV:可能违例; PSV:肯能严重违例。WebKing 支持本地文件的检查测试和创建项 目检查测试网站内容,包括静态、动态和 Ajax 测试。首先需要配置 Webking 的测试标准为 WCAG2.0,如图 1 所示:
图 1. Webking 配置
Webking 配置

对于静态页面可以直接拷贝页面源代码进行静态检查,对于静态网站也可创建项目进行扫描,如图 2 所示:
图 2. 创建静态项目
创建静态项目

在 startURL 处输入 URL 地址或者对于本地文件指定本地路径进行测试。对于动态网站 Webking 提供了录制功能,在用户操作网站的时候录制然后回放测试。
图 3. 创建动态项目
创建动态项目

而对于越来越广泛的 Ajax 应用 Webking 还提供了 Ajax 的功能测试。WebKing 可以检查出任何不符合规范的 HTML 并且提供了详细的修改参考,可以帮助开发人员迅速的定位问题并解决。

JAWS 是 Freedom Scientific 公司的一款读屏软件,现在的版本是 11.0.734. 读屏软件的工作原理是将整个页面的内容存储在一个虚拟的 缓冲区内,用户可以在这个缓冲区内通过键盘浏览并听到相应的内容。浏览的方式可以是一个字符一个字符的,或者是一行一行的。 当用户需要与应用交互的时候则需要切换到另外一个模式,不能再依赖于这个虚拟的缓冲区了,需要跳出这个缓冲区去跟应用交互。JAWS 从 9 开始就已经支持对于普通的 Form 元素自动切换到交互模式了。使用 JAWS 的时候不能使用鼠标,否则会导致虚拟缓冲区出现错误,从而使得读出来的内容很乱。另外的一个正确的测试方式是首先启动 JAWS,然后在打开浏览器,输入对应的 URL,当整个页面加载结束 的时候再开始操作。在加载的过程中,JAWS 会提示页面已经加载的百分比。这样才能保证这个虚拟的缓冲区存储内容的正确性。

开发和测试可访问 Web 应用的步骤

开发和测试可访问的 Web 应用主要的有以下几个步骤:

  • Webking 进行静态检查,通常由开发人员在单元测试时进行,检查 HTML 页面中不满足 CI162 所对应列表的项。目前由于 WebKing 不支持 ARIA,很多 ARIA 的标签不能被正确的识别,所以 WebKing 检查出的错误需要一一去检查区别是真正的违反 Checklist 还是由于 WebKing 不能识别 ARIA 的标签引起的。
  • 键盘支持,要求所有能通过鼠标完成的操作用键盘都能达到同样的效果。
  • 高对比度的支持:在高对比度模式下,屏幕只有黑白两色,要保证 Web 应用在这种模式下不丢失信息。
  • 读屏软件的支持,通常由测试人员完成。测试人员模拟盲人使用读屏软件,要保证页面上的内容基本都能为读屏软件所识别,并且能完成各种操作。

开发最佳实践

开发一个可访问的 Web 应用不仅需要工具的支持,浏览器的支持,还需要开发人员遵循一定的规范提供对应的元素信息,才能达到最终的目的。下面着重介绍一些开发中的最佳实践。

关于 Image

1. 图片或者动画均需提供 Alt 信息,使得读屏软件可以将图片动画的内容清楚的读出来。如图 4 所示:
图 4.Cat 图片
Image

对应的 HTML 如下:
清单 1. Image 的 HTML

				
 <img src="cat.gif" alt="Image about cat" />

 

2. 对于某些用于装饰性的图片,则需设置 alt 为空,使得读屏软件可以忽略此元素。如图 5 的用于装饰页头的图片,实际并没有传递有价值的信息。
图 5. 装饰性图片
Image

对应的 HTML 如下:
清单 2. 装饰性 Image 的 HTML

				
 <img src="ring.gif" alt="" />

 

必须设置一个空 alt 属性的目的是为了能通过 Webking 的检查,并且使得读屏软件能够忽略此元素。

3. 对于图表文件,alt 属性的设置则需要简明扼要的表达出图表的信息,并不用把里面的细节都详细得描述出来。例如下面的图 6:alt 信息设置为销售额从 1996 年到 2004 年间持续稳定增长,从 400 万增长到了 1600 万。并不需要把每一年的增长额都详细得描述出来。
图 6. Image 图表
Image

4. 对于放在链接里面的图片,如果已经有文字的说明,alt 也设置为空,这样避免读屏软件重复同样的内容。如下面的 HTML:
清单 3. 无需重复设置 alt 的 Image

				
 <a href=”http://apple.com/iphone/”> 
	 <img src=”iphone.jpg” alt=””>Apple iPhone 
 </a>

 

A 的内容已经指明了这是个苹果手机,IMG 的 alt 属性就没必要再设置一次了。否则读屏软件会连续读两次重复的内容,引起混乱。

5.CSS 将样式跟结构分离,使得 HTML 代码结构清晰。很多装饰性的图片也都放在 CSS 里面来加载,带来的一个问题就是在 CSS 里面的图片在高对比度模式下都无法显示。如果这个图片并不仅仅是装饰性的,还可以触发功能,那就需要从 CSS 里面拿出来,当成一个独立的 IMG 或者 INPUT 元素。例如下面的一个提示保存的图片
图 7. 保存图片
Image

写在 CSS 里面的做法是:
清单 4. 图片写在 CSS 里面

				
 <div class=” save_button” /> 
 .save_button{ 
	 background: url("images/save_button.png"); 
	 width: 33px; 
	 height: 33px; 
	 vertical-align:middle; 	
 }

 

这样当用户切换到高对比度模式,这个图片就是一片空白,用户无法再去点击保存。修改如下:
清单 5. 将 CSS 里面的图片拿出来

				
 <img src=“images/save_button.png” alt=“save”/> 

 <input type=“image” src=“images/save_button.png” alt=“save”/>

 

6. 在一个图片列表里面选中某个图片,区别选中去否我们通常的做法是用边框的颜色来标识。如下图,选中的图片边框为蓝色
图 8. 图片被选中的正常效果图
Image

清单 6. 图片被选中时对应的 CSS

				
 .selectedIcon{ 
	 border:5px solid #ACC6F3; 
 } 
 .unSelectedIcon{ 
	 border:5px solid #C0D4F7; 
 }

 

但这样的一个实现实际上违反了可访问检查列表中的一项:不能仅仅通过颜色来区分不同的元素,因为在高对比度下只有黑色或白色,这样的区分在高对比度下是没有任何作用的。我们很容易想到的一种办法就是只有选中的时候才加边框,未选中时则没有边框,这样就可以区分出来了。修改如下:
清单 7. 图片被选中时修改后的 CSS

				
 .selectedIcon{ 
	 border:5px solid #ACC6F3; 
 } 
 .unSelectedIcon{ 
	 border:0 none; 
 }

 

这样引起的问题是,图片的布局在选中的时候会浮动,增加了 5px 的边框,看起来效果就很差。那么怎么保证布局又满足可访问性的要求呢? 可以在上面 CSS 的基础上通过 padding 属性使得布局正确:
清单 8. 图片被选中时正确的 CSS

				
 .selectedIcon {border:1px solid #ACC6F3; 	 padding:4px;} 
 .unSelectedIcon {border:0 none; 	 padding:5px;}

 

这样保证整体的边界都是 5px,在高对比度下的效果如图 9 所示:
图 9. 图片被选中时的高对比度效果图
Image

关于 Table

Table 分为两类:一类是做布局的 table,一类是数据 table。对于布局用的 table,读屏软件没必要知道这是一个表,可以通过设置 role=presentation 使 JAWS 忽略这个表,只关注里面的内容。对于数据表格,则需要设置 caption 属性,说明整个表是用来做什么的,使得 JAWS 可以告诉用户这个表的作用。对于每一个单元内的数据,还应该通过 th 属性使得 JAWS 能识别这个数据的表头是什么。对于复杂表,可以通过 id 和 header 属性来标识。如图 10 所示 :
图 10. 数据图表
Image

以第一行的数字 5 为例,正常人可以很容易得看出 5 指的是一年级 Mr.Henry 老师这个班的男生有 5 个,但当 JAWS 面对这个数字 5 的时候,怎么能识别出来呢?通过 header 来标识表头,header 的值就指向对应表头的 id。对应的 HTML 如下:
清单 9. 数据图表

				
 <tr> 
	 <th id="class"> Class </th> 
	 <th id="teacher"> Teacher </th> 
	 <th id="boys"> #of Boys </th> 
	 <th id="girls"> #of Girls </th> 
 </tr> 
 <tr> 
	 <th id="1stgrade" rowspan="2"> 1st Grade </th> 
	 <th id="MrHenry" headers="1stgrade teacher"> Mr . Henry </th> 
	 <td headers="1stgrade MrHenry boys"> 5 </td> 
	 <td headers="1stgrade MrHenry girls"> 4 </td> 
 </tr> 
 <tr> 
	 <th id="MrsSmith" headers="1stgrade teacher"> Mrs . Smith </th> 
	 <td headers="1stgrade MrsSmith boys"> 7 </td> 
	 <td headers="1stgrade MrsSmith girls"> 9 </td> 
 </tr> 
 <tr> 
	 <th id="2ndgrade" rowspan="3"> 2nd Grade </th> 
	 <th id="MrJones" headers="2ndgrade teacher"> Mr . Jones </th> 
	 <td headers="2ndgrade MrJones boys"> 3 </td> 
	 <td headers="2ndgrade MrJones girls"> 9 </td> 
 </tr> 
 <tr> 
	 <th id="MrsSmith" headers="2ndgrade teacher"> Mrs . Smith </th> 
	 <td headers="2ndgrade MrsSmith boys"> 4 </td> 
	 <td headers="2ndgrade MrsSmith girls"> 3 </td> 
 </tr> 
 <tr> 
	 <th id="MrsKelly" headers="2ndgrade teacher"> Mrs . Kelly </th> 
	 <td headers="2ndgrade MrsKelly boys"> 6 </td> 
	 <td headers="2ndgrade MrsKelly girls"> 9 </td> 
 </tr>

 

关于 Form

Form 元素需要关联一个 label 元素,所有的 button 都已经有了一个隐含的 label,所以不再需要显示关联。对于 Input,Select, Checkbox, Radio button 则都需要显示一个 label 元素。这样 JAWS 在面对这个表单元素的时候才能告诉用户这个表单的作用。例如下面清单 10 中的 input, JAWS 会告诉用户这个是需要输入名字的一个输入框。当 label 属性不方便使用的时候,还可以通过 title 属性达到相同的效果,也可以满足 Webking 检查的需要。清单 10 中的两种写法都可以。但前提是 Name 不需要被显示出来。当 title 和 label 都设置的时候 title 会被 JAWS 忽略。
清单 10. Form 元素示例

				
 <label for="name1">Name:</label> 
 <input name="name" id="name1" size="30" /> 
或 
 <input name=”name” id=”name1” size=”30” title=”name”>

 

当一个表单元素如果前后都需要描述的时候, label 就显得力不从心了。ARIA 规范的出现解决了这一问题。aria-labelledby 属性可以设置多个值,说明这个表单元素是被那些值所描述的, aria-describedby 属性则更详细的扩展了这个描述。如图 11 所示:
图 11. 需要多个 Label 描述的输入框
Image

当 JAWS 把焦点放在 10 上的时候,会告诉用户 10 表示的是 10 分钟刷新一次。对应的 HTML 代码如清单 11 所示。aria-required 的属性标识这个元素是必须的,JAWS 识别此元素并告知用户必须输入此元素。我们可以看到中间的 input 元素被多个元素来描述(aria-labelledby 中的几个 id 值),这样 JAWS 就能够识别这个标签,并且按照这个标签的顺序读出前后的 label, 并且提示用户如果还有更详细的描述以及如何获取这个更详细的描述。当用户需要时,aria-describedby 所对应的元素信息就会被读出来。增强了视力有障碍人士与普通人了解内容的一致性。
清单 11. 需要多个 Label 描述的输入框

				
 <div> 
	 <span id="labelRefresh"> 
		  <label for=“refreshTime">Refresh after</label> 
	 </span> 
	 <input id=“refreshTime" type="text" aria-describedby=“refreshDescriptor" 
	 aria-labelledby=" labelRefresh refreshTime refreshUnit" value="10"/> 
	 <span id=“refreshUnit"> minutes</span> 
 </div> 
 <div id=“refreshDescriptor">Allows you to specify the number of minutes of 
 refresh time.</div>

 

关于 Tabindex 与获取焦点的顺序

Tabindex 属性的使用可以使得原本无法取得焦点的元素获取焦点。目的是为了使用户可以用键盘访问任何可以用鼠标访问的元素。我们知道,使用 Tab 键可以按文档顺序 tab 到所有可以获取焦点的元素。Tabindex 可以设置为 -1, 0 或者是任何自然数。

  • Tabindex = 0 就使原本无法获取焦点的元素可以在用户 tab 的时候获取焦点,并且按照文档顺序排列。
  • Tabindex = -1 使得元素可以获取焦点,但当用户用 tab 键访问的时候并不出现在 tab 的列表里面。可以方便的通过 Javascript 设置上下左右键的响应事件。非常有利于应用小部件(widget)内部的键盘访问。
  • Tabindex 设置为大于 0 的数字则可以控制用户 Tab 时候的顺序,一般很少用。

当用户使用 Tab 键浏览页面时,元素获取焦点的顺序是按照 HTML 代码里面元素出现的顺序排列的,有时跟实际看到的页面顺序并不一致。例如图 12 所示的页面:
图 12. 图片被选中时的高对比度效果图
Image

按照页面顺序,tab 的顺序为自左向右,可实际上操作的时候却发现“search all”出现在了“go to edit”的前面。对应的 HTML 代码如清单 12 所示:
清单 12. 页面获取 focus 的顺序

				
 <div> 
   <span style=”float:left;”> 
			 welcome page 
   </span> 
   <span style=”float:right;margin-left:6em;”> 
			 search all 
   </span> 
   <span style=”float:right;”> 
		   go to edit 
   </span> 
 </div>

 

原来是通过 float:right 达到了布局上的效果,实际文档顺序确实是 search all 在前面的。所以为了不引起混淆,最后能保持代码的顺序与实际呈现出来的页面上的顺序一致。可以修改上面的代码为清单 13 所示:
清单 13. 页面获取 focus 的顺序 — 调整后

				
 <div> 
   <span style=”float:left;”> 
			 welcome page 
	 </span> 
	 <span style=”float:right;width:15em;”> 
		<span style=”float:left;”> 
				   go to edit 
	    </span> 
		<span style=”float:right;”> 
				  search all 
	    </span> 
	 </span> 
 </div>

 

关于隐藏的内容

隐藏的内容分为两种,一种是为了布局的需要,在条件满足的情况下才会显示出来;另一种是只给读屏软件读的内容:有时候我们为了使读屏软件更准确的读取信息,会提供一些额外的描述来达到此效果,但为了不给正常用户带来困扰,这些内容对正常用户来说是隐藏起来的。隐藏内容我们通常用 display:none 或者 visibility:hidden 来表示,但读屏软件同样也会忽略这类内容。那如何隐藏内容又能使读屏软件读出来呢?另外一种隐藏内容的方式是使用绝对定位使得内容不出现在当前屏幕上,如:{position:absolute;top:-30000px;} 所以在选择使用哪种方式隐藏内容时就需要慎重考虑,display:none visibility:hidden 对任何人都是隐藏的,如果想只给读屏软件读到就需要使用上面的绝对定位方式。例如在图 13 所示的菜单的选中项上加上如下的 css:
清单 14. 只给读屏软件读的内容

				
 <span>  is selected</span> 
 .access{
 position:absolute;
 top:-30000px;
 }

图 13. 菜单
Image

这样当用户使用 JAWS 浏览每一个菜单项时,在选中项上就能听到哪一项是当前的所选中。

高对比度模式的小技巧

系统切换到高对比度模式,只有黑白两色,很多在正常模式下依靠颜色来区分的(如界面边界)都无法辨识了,写在 CSS 里面的很多图片也都无法显示出来。此时就需要在高对比度下增加边界或者另外 DOM 节点来显示同样的内容。Dojo 的 WAIState Api 提供了一种方式来判断系统是否处于高对比模式,如果是则在 body 上增加 dijit_a11y 的一个 CSS。这样可以在正常模式下显示一个 DOM 节点在高对比度下显示另外一个 DOM 节点,从而方便的区分。如图 14 所展示的正常模式与高对比模式下的对比:
图 14. 高对比模式与正常模式的对比
Image

正常模式下如左图所示,子菜单通过一个图片标识,但这个图片是在 CSS 里面设置的,切换到高对比度模式即无法显示出来。此时,我们增加一个在高对比度模式下才显示出来的节点,达到如图右所示的效果,在高对比度下显示一个 + 号。代码清单如清单 15 所示,在高对比模式下,dijit_a11y 加在 body 上,dijitMenuExpandA11y 所对应的 DOM 即应用右面的 CSS 得以显示出来。
清单 15. 正常模式与高对比模式显示不同的 Dom 节点

				
<td waiRole="presentation">
<div dojoAttachPoint="arrowWrapper" style="visibility: hidden">
<img src="${_blankGif}" alt="">
<span>+</span>
</div> 
</td>  

tundra .dijitMenuExpand { 
width: 7px; 
height: 7px; 
background-image: url('images/spriteArrows.png'); 
background-position: -14px 0px; 
} 
.dijitMenuExpandA11y {display: none; } 
.dijit_a11y .dijitMenuExpandA11y {display: inline; }

 

总结

本文介绍了开发测试可访问无障碍的 Web 应用的工具,步骤以及开发中的最佳实践。应用这些最佳实践与小技巧能帮助您在开发中迅速的为您的 Web 应用提供 A11Y 的支持。

 

参考资料

此条目发表在 技术 分类目录。将固定链接加入收藏夹。

发表评论

电子邮件地址不会被公开。 必填项已用*标注