让屏幕阅读器阅读使用 JavaScript 添加的新内容
Posted
技术标签:
【中文标题】让屏幕阅读器阅读使用 JavaScript 添加的新内容【英文标题】:Getting screen reader to read new content added with JavaScript 【发布时间】:2011-04-09 21:25:15 【问题描述】:加载网页时,屏幕阅读器(如 OS X 随附的屏幕阅读器或 Windows 上的 JAWS)将阅读整个页面的内容。但是假设您的页面是动态的,并且当用户执行操作时,新内容会添加到页面中。为简单起见,假设您在 <span>
的某处显示一条消息。如何让屏幕阅读器阅读新消息?
【问题讨论】:
屏幕阅读器在获得焦点时会阅读表单字段和链接。因此,一种可能性是在文本周围放置一个锚点并将焦点设置在该锚点上。使用 CSS,您可以让链接不显示为查看页面的用户的链接。但是这种方法不是很令人满意,因为屏幕阅读器用户会被错误地认为这是一个链接。 将 tabindex 添加到任何元素,它就会变得可读,我相信(tabindex=-1 使其可编写脚本但不可选项卡)。我经常在单击链接后以编程方式将焦点发送到新内容(如选项卡切换器或手风琴) - 但它不一定是可聚焦的链接。阅读 tabindex。 【参考方案1】:WAI-ARIA 规范定义了几种屏幕阅读器可以“观看”DOM 元素的方式。最受支持的方法是aria-live
属性。它有模式off
、polite
、assertive
和rude
。自信程度越高,就越有可能打断屏幕阅读器当前正在说话的内容。
以下内容已在 Firefox 3 和 Firefox 4.0b9 下使用 NVDA 进行了测试:
<!DOCTYPE html>
<html>
<head>
<script src="js/jquery-1.4.2.min.js"></script>
</head>
<body>
<button onclick="$('#statusbar').html(new Date().toString())">Update</button>
<div id="statusbar" aria-live="assertive"></div>
</body>
同样的事情可以是accomplished 与 WAI-ARIA roles role="status"
和 role="alert"
。我收到了不兼容的报告,但无法重现它们。
<div id="statusbar" role="status">...</div>
【讨论】:
为了清楚起见,aria-live
的唯一有效值是 off
、polite
和 assertive
。如果有人对与活动区域相关的角色的默认设置感到好奇,或者只是想看看他们做了什么,我写了一个小操场来展示活动区域的运行情况:schne324.github.io/live-region-playground
这不适用于我在 Mac 上使用 Firefox 41.0.2 你有什么线索吗?适用于 Safari 和 Chrome
只是添加到 aria-live 的有效值,实际上有 4 个值。 off、polite、assertive 和 rude,如此处的文档所述:msdn.microsoft.com/en-us/library/windows/apps/hh465711.aspx
WAI 标准有 3 种状态(关闭、礼貌、自信)w3.org/TR/wai-aria/states_and_properties#aria-live 微软添加了非标准的“粗鲁”,看起来与标准的“自信”相匹配
只是想我会为有效的aria-live
值提供更新的链接。在发表此评论时,他们确实关闭、礼貌和自信:https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-live#values【参考方案2】:
这是一个经过改编的现实世界示例——这个高级标记已经通过 JS 从带有链接的无序列表转换为选择菜单。真正的代码要复杂得多,显然不能完整地包含在内,所以请记住,在生产使用时必须重新考虑这一点。为了使选择菜单可以通过键盘访问,我们注册了 keypress 和 onchange 事件,并在用户从列表中退出时触发 AJAX 调用(注意浏览器在 onchange 事件时间上的差异)。这是一个严肃的 PITA,可以访问,但它是可能的。
// HTML
<!-- select element with content URL -->
<label for="select_element">State</label>
<select id="select_element">
<option value="#URL_TO_CONTENT_PAGE#" rel="alabama">Alabama</option>
</select>
<p id="loading_element">Content Loading</p>
<!-- AJAX content loads into this container -->
<div id="results_container"></div>
// javascript (abstracted from a Prototype class, DO NOT use as-is)
var selectMenu = $('select_element');
var loadingElement = $('loading_element');
var resultsContainer = $('results_container');
// listen for keypress event (omitted other listeners and support test logic)
this.selectMenu.addEventListener('keypress', this.__keyPressDetector, false);
/* event callbacks */
// Keypress listener
__keyPressDetector:function(e)
// if we are arrowing through the select, enable the loading element
if(e.keyCode === 40 || e.keyCode === 38)
if(e.target.id === 'select_element')
this.loadingElement.setAttribute('tabIndex','0');
// if we tab off of the select, send focus to the loading element
// while it is fetching data
else if(e.keyCode === 9)
if(targ.id === 'select_element' && targ.options[targ.selectedIndex].value !== '')
this.__changeStateDetector(e);
this.loadingElement.focus();
// content changer (also used for clicks)
__changeStateDetector:function(e)
// only execute if there is a state change
if(this.selectedState !== e.target.options[e.target.selectedIndex].rel)
// get state name and file path
var stateName = e.target.options[e.target.selectedIndex].rel;
var stateFile = e.target.options[e.target.selectedIndex].value;
// get the state file
this.getStateFile(stateFile);
this.selectedState = stateName;
getStateFile:function(stateFile)
new Ajax.Request(stateFile,
method: 'get',
onSuccess:function(transport)
// insert markup into container
var markup = transport.responseText;
// NOTE: select which part of the fetched page you want to insert,
// this code was written to grab the whole page and sort later
this.resultsContainer.update(markup);
var timeout = setTimeout(function()
// focus on new content
this.resultsContainer.focus();
.bind(this), 150);
.bind(this)
);
【讨论】:
以上是关于让屏幕阅读器阅读使用 JavaScript 添加的新内容的主要内容,如果未能解决你的问题,请参考以下文章