让屏幕阅读器阅读使用 JavaScript 添加的新内容

IT技术 javascript accessibility screen-readers
2021-02-17 05:06:06

加载网页时,屏幕阅读器(如 OS X 附带的或 Windows 上的 JAWS)将阅读整个页面的内容。但是假设您的页面是动态的,并且随着用户执行操作,新内容会添加到页面中。为简单起见,假设您在<span>. 如何让屏幕阅读器阅读新消息?

2个回答

WAI-ARIA规范定义了几种方法,使屏幕阅读器可以“看” DOM元素。最受支持的方法是aria-live属性。它有模式offpoliteassertiverude自信程度越高,就越有可能打断屏幕阅读器当前所说的内容。

以下已在 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>

同样的事情可以完成与WAI-ARIA角色 role="status"role="alert"我收到了不兼容的报告,但无法重现它们。

<div id="statusbar" role="status">...</div>
这在 Firefox 41.0.2 的 Mac 中对我不起作用你有什么线索吗?适用于 Safari 和 Chrome
2021-04-18 05:06:06
需要明确的是,唯一有效的值aria-liveoff,politeassertive如果有人对与实时区域关联的角色的默认设置感到好奇,甚至只是想看看他们做了什么,我写了一个小操场来展示实时区域的运行情况:schne324.github.io/live-region-playground
2021-05-01 05:06:06
只是为了添加 aria-live 的有效值,实际上有 4 个值。关闭礼貌自信粗鲁,如以下文档中所述:msdn.microsoft.com/en-us/library/windows/apps/hh465711.aspx
2021-05-04 05:06:06
WAI 标准有 3 个状态(关闭、礼貌、断言)w3.org/TR/wai-aria/states_and_properties#aria-live 微软添加了非标准的“粗鲁”,这似乎与标准的“断言”相匹配
2021-05-04 05:06:06

这是一个适应现实世界的例子——这个上级标记已经通过 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)
    });
}