为您的 HTML/JavaScript 应用添加辅助功能
内置于平台之中的辅助功能是 Windows 8 应用的一大独有特征。借助辅助功能特性,可以轻松拓展您的应用的受众范围。开发人员和用户对我们的这一做法好评如潮,而且我们也已经进一步完善了这一平台。现在,我们将向您介绍如何在设计阶段将 HTML 和 JavaScript 应用中的辅助功能纳入考虑范畴,并为您展示如何为一些常见 UI 模式实施和测试辅助功能,之后还将为您提供一些我们在创建自定义 UI 控件时所采用的最佳做法,最后再与您探讨通过解决辅助功能的问题而触及所有 Windows 用户的机会。
本篇博文中所提到的信息和示例均为 HTML/JavaScript 特定的内容,但是我们也在 XAML 应用中内置了辅助功能。您可使用开发工具所提供的模板和控件,并参考开发中心内现有的指导和应避免的做法来创建包含辅助功能的 XAML 应用。
辅助功能意义重大
在构建 Windows 8 的过程中,我们希望所有用户都能从丰富的应用生态系统中获益,并让多姿多彩的包含辅助功能的应用充实用户的日常生活。因此我们将辅助功能内置于 Visual Studio 模板、IntelliSense、常见控件之中,并提供了多个测试工具和一个方法来声明该应用包含辅助功能。启用您应用中的辅助功能至关重要,因为这将影响全球约 15% 的人口。我们希望您能够触及这一用户群,并采用我们内部在自己的应用中所采用的一些最佳做法。这些做法也将是在您的应用中包含辅助功能之旅的一个绝佳起点。在本篇博文中,您将了解到如何:
- 识别辅助功能应用场景以及如何在您的应用中轻松支持这些场景。
- 使用平台控件,因为您可免费获得许多内置的辅助功能。
- 确定您的应用是否符合辅助功能的要求。
- 规划辅助功能测试,使用 SDK 工具(Inspect 和 UI Accessibility Checker),专注于为需要使用屏幕阅读器、仅使用键盘、和/或需要变更对比度或缩放比例的用户启用应用场景。
- 了解应用商店辅助功能声明的工作原理,以及该声明将如何帮助您触及更多用户。
通过遵循最佳做法,您不仅可理解残障用户将如何体验您的应用,而且您还可开发出符合更广泛用户需求的应用。
包含辅助功能的应用的要点
应用中的重要元素包括磁贴、应用栏、ListView 和导航。因此,让我们一同来看看这些元素,并了解为其添加辅助功能是多么简便。
磁贴
磁贴在“开始”屏幕中代表着您的应用,并且是用户体验您的应用的首个位置。磁贴已为屏幕阅读体验默认包含了辅助功能!为了启用高对比度体验,您只需要将磁贴的高对比度版本添加至 Visual Studio 项目即可。
图 1:音乐、视频和 Xbox LIVE 游戏磁贴可支持高对比度黑白主题。粗体字体可识别其以上磁贴的版本。
此外,您还可设置文本前景色和背景色,以符合 4.5:1 的对比度,从而让更多弱视用户使用您的应用。使用一个 W3C 推荐的工具来比较前景色和背景色代码,进而验证对比度(深色 = #2A2A2A,浅色 =#FFFFFF)。
图 2:磁贴徽标文本的 Visual Studio 清单。
仅左侧的结果磁贴文本拥有充足的文本对比度。
为您的磁贴确保卓越的高对比度体验和充足的徽标文本对比度将让您的应用对弱视用户更具吸引力。
应用栏
应用栏将让用户快速、轻松地使用与应用相关的命令,因此应用栏需包含辅助功能。
与磁贴一样,如果您使用标准 HTML 控件,那么应用栏命令在默认情况下将包含辅助功能。例如,如果您像此处标记中的情形一样在使用平台按钮控件,那么您的命令将在默认情况下包含完整辅助功能,完全不需要您进行任何其他操作!
示例 1:标准底部应用栏的标记。此处不包含任何特殊辅助功能属性,所有内容都将内置其中。
<div id="appbar" data-win-control="WinJS.UI.AppBar"> <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdAdd',label:'Add',icon:'add', section:'global'}"> </button> <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdRemove',label:'Remove',icon:'remove', section:'global'}"> </button> <hr data-win-control="WinJS.UI.AppBarCommand" data-win-options="{type:'separator',section:'global'}" /> <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdDelete',label:'Delete',icon:'delete',section:'global'}" > </button> </div>
图 3:应用栏在默认情况下将包含辅助功能并支持屏幕阅读、仅使用键盘、高对比度和文本对比度。
使用应用栏来显示常用的命令可方便弱视用户使用。例如,在我们所开发的音乐应用中,应用栏中的播放控件就包含辅助功能,屏幕阅读器可像“讲述人”一样读出内容。
图 4:音乐应用中应用栏内的播放控件可让用户快速、轻松地使用。
与磁贴中的情形类似,您应确保您的应用栏元素可支持高对比度,而且您所选择的颜色应符合文本对比要求。
ListView 控件
ListView(如图 5 所示)是最常用的 WinJS 控件之一。其可为用户查看并管理数据收藏集提供丰富体验。正如同我们所探讨过的其他平台控件,ListView 在默认情况下将包含完整辅助功能!
图 5:应用中常常使用列表视图。
Visual Studio 2012 网格应用模板中的下一标记则展现了如何为 ListView 控件设置辅助功能属性。其显示了如何:
- 借助 ARIA 标签为 ListView 控件设置辅助功能名称。
- 定义列表项目模板数据绑定:向数据源标题列映射 IMG Alt 属性。
请注意列表项目的辅助功能名称将由系统基于列表项目文本内容而默认设置。
示例 2:Visual Studio 2012 网格应用模板包含辅助功能。突出显示的属性被设置包含辅助功能。
<!-- These templates display each item in the ListView declared here. --> <div class="itemtemplate" data-win-control="WinJS.Binding.Template"> <img class="item-image" src="#" data-win-bind="src: backgroundImage; alt: title" /> <div class="item-info"> <h4 class="item-title" data-win-bind="textContent: title"></h4> <h6 class="item-subtitle " data-win-bind="textContent: subtitle"></h6> <h4 class="item-description" data-win-bind="textContent: description"></h4> </div> </div> <!-- The content that will be loaded and displayed. --> <div class="fragment groupeditemspage"> … <section aria-label="Main content" role="main"> <div class="groupeditemslist" aria-label="List of groups" data-win-control="WinJS.UI.ListView" data-win-options="{ selectionMode: 'none' }"> </div> </section> </div>
图 6:包含辅助功能的 Visual Studio 2012 网格应用项目模板显示了
SDK 工具 Inspect 中的辅助功能属性。
在设置了辅助功能属性之后,请确保您列表项目的内容可支持高对比度,同时您所选择的颜色符合文本对比度的要求。
高效的键盘导航
键盘导航至关重要,原因主要有几点。发烧友们仍然依赖于使用键盘来增强 Windows 的使用体验,而且有一部分 Windows 用户仅使用键盘来导航和使用系统。视力、行动或灵活度有障碍的用户依赖于键盘来支持其计算机使用。因此,当您在设计应用时,需考虑为这些用户提供高效、卓越的键盘导航支持。
而在此我们也向大家宣布一条好消息:我们也已经可让您实现轻松支持键盘导航。所有平台控件都已经内置了键盘导航!所有交互元素在默认情况下将按照选项卡顺序排列,而诸如 ListView 等容器元素也实施了内部箭头键导航,因此您可使用箭头键来穿行于列表之中。使用平台控件可为您免费提供诸多辅助功能,其中包括高效键盘导航。
图 7:少量选项卡停止点和内置的 ListView 箭头
键盘导航可实现键盘高效导航邮件应用。
我们在设计您可能遇到的应用时所遇到的一个有趣问题在于“我是否需要向选项卡顺序添加文本元素,从而让屏幕阅读器阅读这些元素?”
答案是否定的。静态文本不应按照选项卡顺序排列,因为平台已经显示了该文本,而平台也已经在 UI Automation (UIA) 树中显示了该文本,因而实现了屏幕阅读器对其进行访问。“讲述人”和其他屏幕阅读器包含阅读命令(例如,同时按下“Caps”和“M”键可从“讲述人”的指针位置阅读文本)和 UIA 树导航命令(同时按下“Caps”和左/右箭头键)来按顺序阅读所有 UIA 树形元素。因此,您无需为其添加额外选项卡元素。
让您的自定义 UI 包含辅助功能
在前面几个部分中,我们已经了解了内置的辅助功能对您使用标准控件所提供的优势。但是对于复杂应用而言,您可能需要构建自定义 UI。以下将基于我们的经验为您介绍一些有助于为您的 UI 包含辅助功能的提示。
为辅助功能描述自定义 UI
当您使用 HTML/JavaScript 构建包含辅助功能的自定义 UI 时,请查阅 W3C 发布的包含辅助功能的丰富 Internet 应用程序 (ARIA) 标准,以理解当前可用的 ARIA 角色和属性。该标准以及开发中心内有关让您的应用包含辅助功能的指南将有助于您在为 UI 建模并设置辅助功能属性时做出正确选择。让我们一同来看看自定义 UI 的一些常见模式,以及我们为使应用包含辅助功能而所进行工作。如果您遵循我们的提示和指南中的信息,那么您可为自定义 UI 的实施而轻松采用辅助功能。
使用选项卡列表控制内容
Release Preview 中发布的旅游应用为航班搜索表格采用了自定义 UI。尽管该 UI 较为复杂,但是让其包含辅助功能却十分简单。我们通过设置属性而实现了这一点:角色、ARIA 控件和 ARIA 选定。
千里之行,始于选择适当的模式
我们并没有为搜索、日程和状态元素而使用按钮,而是决定在旅游应用中将整个航班搜索表格描述为一个用于导航的 ARIA 选项卡列表,该选项卡列表可让我们提供更多信息。选项卡列表包含作为 ARIA 选项卡的搜索、日程和状态元素,其中包含 ARIA 选定的属性来反映当前选定的选项卡和 ARIA 控件属性来指出相关内容。该方法可让我们为用户提供更多有关 UI 和更丰富的辅助功能体验的信息。
示例 3:Bing 之旅应用、航班搜索、使用选项卡列表和选项卡元素。
<div class="…" role="tablist"> <div … id="flightSearchTripTab" role="tab" aria-controls="flightSearchTripView"> … </div> <div … id="flightSearchFlightSchedulesTab" role="tab" aria-controls="flightSearchFlightSchedulesView"> … </div> <div … id="flightSearchFlightStatusTab" role="tab" aria-controls=" flightSearchFlightStatusView"> … </div> </div> … <!-- Trip view--> <div … role="tabpanel" role="tabpanel" id="flightSearchTripView"> … </div> <!-- Flight status view--> <div … role="tabpanel" id="flightSearchFlightSchedulesView"> … </div> <!-- Flight status view--> <div … role="tabpanel" role="tabpanel" id="flightSearchFlightStatusView"> … </div> _showTabView: function (tab) { … if (tabElement) { WinJS.Utilities.removeClass(tabElement, "flightSearchUnselectedTab"); WinJS.Utilities.addClass(tabElement, "flightSearchSelectedTab"); tabElement.setAttribute("aria-selected", "true"); … } … }
图 8:SDK 工具 Inspect 为 Bing 之旅应用的选项卡列表和选项卡元素显示了辅助功能数据。
如果您在应用中使用 ARIA 控件来显示有关选项卡元素和它们所控制的内容之间的关系的信息,那么用户可(同时按下“Caps”和“插入”键)使用“讲述人”跳转命令将焦点移动至包含链接内容的选项卡。
以编程方式选择选项卡
为了让仅包含触控功能的设备上的旅游应用搜索表格能够与“讲述人”实现无缝配合,我们需要让用户以编程的方式选择选项卡元素(同时按下“Caps”和空格键或双击“讲述人”)。
我们通过将搜索、日程和状态描述为 ARIA 选项卡而完成了这一操作,这样一来平台可将其显示为 UIA SelectionItem 控件模式。反过来,“讲述人”双击的手势将为这些选项卡元素变更 ARIA 选定属性。因此,为了确保向选定的选项卡加载适当的内容,我们还需要为选项卡 ARIA 选定的属性添加一个 propertychange 事件处理程序。示例如下:
示例 4:为 ARIA 选定属性处理 onpropertychange,以检测选项卡选择的编程变更。
tabElement.attachEvent("onpropertychange", selectionChanged); function selectionChanged(event) { if (event.propertyName === "aria-selected") if (event.srcElement.getAttribute("aria-selected") === "true") { // execute code to load the content that corresponds with the selected tab element } else { // execute code for deselected tab, if needed } }
当我们谈论以编程方式控制 UI 时,您还需要思考另一主题以确保“讲述人”触控体验受到支持。这便是包含辅助功能的触控事件。
包含辅助功能的触控事件
考虑到 Windows 8 旨在为触控优先的环境提供卓越用户体验,因此我们建议您使用触控事件来为用户提供流畅的 UI 流和强劲的触控性能。
如果您仅使用触控事件 MSPointerUp 和 MSPointerDown,那么您需要处理 Click 事件来支持屏幕阅读器的辅助功能体验。举例来说,如果用户同时按下“Caps”和空格键或双击,那么这可让“讲述人”与您的 UI 以编程的方式进行交互。将 MSPointerUp 事件处理程序代码封装至单独的函数中,并调用相同函数 (delayedPointerUp) 表格 Click 事件处理程序是您进行该操作的一个方式。以下示例展示了我们是如何在 Bing 应用中完成这一操作的(代码已简化):
示例 5:让触控事件以编程的方式包含辅助功能并启用“讲述人”触控体验的解决方案。
Bing apps, platform\js\utilities.js: element.addEventListener("click", onClick); element.addEventListener("MSPointerUp", onMsPointerUp); … var pointerUpEventObject = null; var pressedElement = null; var isClick = false; function onClick(evt) { isClick = true; delayedPointerUp(); } function onMsPointerUp(evt) { pointerUpEventObject = evt; msSetImmediate(delayedPointerUp); } … function delayedPointerUp() { if (isClick || pointerUpEventObject && (pointerUpEventObject.srcElement == pressedElement || … right button checks…)) { pointerUpEventObject = null; isClick = false; invokeItem(pressedElement); } } …
为了防止 delayedPointerUp 在用户单击鼠标后执行两次(这将触发 Click 和 onMsPointerUp),您可以:
- 使用 msSetImmediate 来延迟 MSPointerUp 调用 delayedPointerUp
- 使用 pointerUpEventObject 变量来保持引用 MSPointerUp 事件对象
- 使用 isClick 变量来跟踪 Click 处理程序是否被执行
- 通过在首次执行 delayedPointerUp 后重置 isClick 和 pointerUpEventObject 变量,防止第二次执行 delayedPointerUp。
通过添加这几行代码,您可启用“讲述人”触控体验,因此双击的手势将以编程的方式激活您 UI 中与交互元素相关的功能。
自动完成
地址控件中的自动完成是我们在邮件应用中所添加的另一项能与屏幕阅读器(如“讲述人”)良好配合的自定义功能。
面向邮件地址控件 (addressbarToField) 的自动完成解决方案背后的理念在于显示两个列表(toDDDDList 和 toL),分别用于进行地址建议和存储选择的联系人。为了向其添加辅助功能,我们将输入字段 (toIF) 角色属性设置为 combobox,以反映出其包含一个相关的下拉列表。我们还将输入字段 (toIF) 设置为 ARIA 控件属性,以设置指向建议列表,该列表将在用户开始键入时显示。这可让“讲述人”为建议列表 (toDDDDList) 播报选择事件,而键盘焦点仍然保持在主输入字段 (toIF)。以下显示了我们的做法:
示例 6:进行自动完成的邮件应用地址字段的辅助功能解决方案。
<div id=" addressbarToField" class="…"> <div id=" toOC" class="…"> <div id="toL" role="listbox" ><!--chosen contacts--></div> <input id="toIF" size="1" type="email" role="combobox" aria-autocomplete="list" aria-controls="toDDDDArea" aria-activedescendant="toDDList0" /> </div> <div id="toDDDDArea" role="group" class="…"> <div id=" toDDDDList" role="listbox"> <div id="toDDList0" role="option" aria-selected="true">…</div> <div id="toDDList1" role="option" aria-selected="false">…</div> … </div> </div> </div>
自动完成解决方案可让用户在输入字段中键入,此时建议列表将显示,而“讲述人”将播报首个建议的联系人。当用户继续键入时,建议列表将减少,导致一个新的选择事件被启用,这也将提示“讲述人”播报列表中新出现的位于顶部的联系人元素。如果用户使用键盘箭头键来上下移动建议列表,那么“讲述人”将继续播报所选定的联系人。键盘的焦点将始终停留于输入字段。
图 9:“讲述人”随着列表变更而阅读建议,Inspect 显示 ARIA 所显示的 UIA 信息(活动子级、控件)
包含辅助功能的图形元素
对于让图形元素包含辅助功能而言,这一点始终充满挑战,这是因为无法采用一个直接的方式让其包含辅助功能。但是最起码,我们能够为该元素设置一个辅助功能名称和角色(通常为 ARIA img),因此使用屏幕阅读器的用户可了解屏幕中的这些元素。如果这些图形元素为交互式元素,那么用户需要能采用一种方式与其交互。
另一方面,如果您可让交互式图形元素包含辅助功能,那么这可提高使用效率,并获得更多客户的积极反馈。其中一个突出的示例就是 Bing 天气应用及其历史天气图。其为“讲述人”键盘应用场景和高对比度主题提供了辅助功能。我们在图表中将每月天气情况显示为包含辅助功能名称的单独 UIA 树形元素,进而实现了这一点。我们将指针所描述的 ARIA 添加至显示于右侧图表旁边的月份历史信息中。随着用户将箭头向左或向右移动突出显示月份,“讲述人”将播报月份名称,并随后阅读该月份的历史信息。以下是代码段:
示例 7:Bing 天气应用,将 ARIA 描述动态设置到当前选定的月份元素。
SetArrowKeyHandler: function (parentNode, chartObject) { … for (var index = 0, len = tickLabels.length; index < len; index++) { tickLabels[index].addEventListener("keydown", function (event) { … if (newMonth) { newMonth.focus(); newMonth.tabIndex = "0"; newMonth.,setAttribute("aria-describedby", "hwModuleShifted"); hwChart.HandleMonthClick(newMonthIndex, chartObject); this.blur(); this.tabIndex = "-1"; this.removeAttribute("aria-describedby"); } }); } }
图 10:Bing 天气,历史天气图 — 箭头键导航可让“讲述人”阅读月份信息。
利用 ARIA 引用元素
如果您使用诸如 ARIA 控件或 ARIA 描述等 ARIA 关系属性来引用其他元素,那么请确保目标元素必须被平台识别为 UIA 对象。您可使用 Inspect 来在 UIA 树中定位该元素,进而对此进行验证。除非其被 ARIA 隐藏 ="true" 的树显式隐藏,或设置其样式为视觉隐藏。
在下一示例中,引用的“A” DIV 标记未包含于输入字段辅助功能名称,也未包含于 UIA 树中,这是因为默认情况下系统不会将 DIV 标记视为一个 UIA 对象。相反,“B”DIV 标记包含于输入字段名称,而且将显示于 UIA 树中,这是因为其包含一个角色属性集。
示例 8:引用的 DOM 元素必须是显示于 UI 树或显式隐藏于 UI 树中的常规 UIA 对象。
<input type="text" aria-labelledby="idA idB" /><div id="idA">A</div><div id="idB" role="heading">B</div>
为辅助功能测试应用场景
测试应用的辅助功能的目标在于确保无论用户是否为残障人士,其均可体验您的应用。这意味着需测试您的应用中每个 UI 元素的辅助功能,验证用户能否端到端地使用“讲述人”(使用键盘和触控设备)来完成应用的每个任务,获得高对比度(黑白),以及确保可放大所有内容(参阅设置 -> 更改 PC 设置下方的辅助功能设置)。
测试“讲述人”作用很大,因为“讲述人”将依赖于 UI 自动化 API 来阅读并与您的 UI 交互,而 UI 自动化 API 将支持我们此前曾提到过的 ARIA 标准。在仅包含触控功能的设备上,“讲述人”可让您在 UI 元素上方移动手指来检查 UI 并使用手势来移动键盘焦点,导航 UIA 树,调用或选择元素,在不同模式中阅读文本内容,以及进行更多操作。
借助应用商店辅助功能声明触及更多用户
您在采用本篇博文中所介绍的几个示例创建和测试包含辅助功能的应用,并遵循辅助功能指导原则之后,您可声明您的应用包含辅助功能!这意味着相比其他未考虑辅助功能的应用,您的应用可被更广泛的用户使用。
为让您的努力获得回报,并扩大您的用户基础,请在发布过程中选中辅助功能复选框,以声明您的应用包含辅助功能。
图 11:Windows 应用商店上架页面中显示了应用是否包含辅助功能的复选框选项。
如果您声明您的应用包含辅助功能,那么用户可在其首选项中进行相应选择以筛选海量应用。通过采用这种方式,用户可迅速找到他们可借助屏幕阅读器使用的应用,并放大所有内容,或使用高对比度设置。
结论
抽时间为您的应用添加辅助功能将是一笔宝贵的投资,因为这将让更广大的用户使用您的应用,并改善您的应用的质量。当您使用默认包含了辅助功能的标准控件创建应用时,这一工作中的大部分就已经完成。但是如果您需要添加更多复杂体验或自定义 UI,则请遵循我们在此处所提供的最佳做法,并参阅参考资料,以让您的应用包含辅助功能。
--Jennifer Norberg,项目经理主管