如何使用 HTML5 为屏幕阅读器创建有序列表
介绍
Web 可访问性是确保每个人都能平等、平等地访问 Web 的一个重要方面。这意味着网站也必须可供残障人士使用和访问。在构建 React 应用程序时,很容易忘记我们正在构建的应用程序的可访问性。在本指南中,我们将集中精力让 Web 更适合视障人士。
屏幕阅读器
首先,让我们对屏幕阅读器进行简要的解释,以便我们了解用户的需求。
“屏幕阅读器从元素中获取语义信息,并为有视力障碍的用户生成替代的语音 UI。”
默认情况下,HTML5 列表具有正确的语义,屏幕阅读器会将其读出为列表。但在构建 Web 应用程序时,由于一个或多个原因,我们可能无法使用原生 HTML5 列表。那么,ARIA角色就可以派上用场了。
可访问性富互联网应用程序 (ARIA)
ARIA代表可访问性富互联网应用程序;它是一种规范,包含一组可添加到元素的属性。它可以操纵可访问性树并添加其他语义。可访问性树只是 DOM 树的一个子集。浏览器会删除所有表示元素并修改 DOM 树,使其适用于屏幕阅读器等辅助技术。这种重新构建的 DOM 树称为可访问性树。
最好使用原生 HTML 元素来获得正确的语义,但有时在处理第三方代码或开发复杂的 UI 时,您可能必须构建自定义元素。我们可以使用 ARIA 属性为这些自定义元素赋予正确的语义,以便屏幕阅读器可以正确地读出它们。
屏幕阅读器播报的有关有序列表或无序列表的一些信息包括:
- 列表的大小
- 列表中每个项目的位置
- 当用户离开一个列表并进入另一个列表时
虽然这取决于个人的屏幕阅读器,但以上几点是最常见的。
示例(终于!一些代码)
让我们首先了解如何使用ARIA属性来使我们的文档可访问。
HTML 元素可以具有list或listitem的 role 属性,以便屏幕阅读器可以将其解释为列表。有序列表或无序列表,对于 ARIA 来说都是一样的。在遍历本机列表元素时,屏幕阅读器会在有序列表项开始之前宣布数字,并在无序列表项开始之前宣布“项目符号”,但它永远不会宣布列表是有序的还是无序的;它只会在遍历列表时变为有序的。
<div role="list">
<div role="listitem">HTML</div>
<div role="listitem">CSS</div>
<div role="listitem">JavsScript</div>
</div>
在上面的代码片段中,div 标签用于表示列表和列表项。屏幕阅读器会将其解释并读出为“包含三个项目的列表”,并且在每个列表项的末尾,它会读出“listitem”。但这并不能让用户了解它是有序列表还是无序列表。
为了在每个列表元素前显示一个数字,我们可以使用aria-label属性。
<div role="list">
<div role="listitem"><span aria-label="1"></span> HTML</div>
<div role="listitem"><span aria-label="2"></span> CSS</div>
<div role="listitem"><span aria-label="3"></span> JavaScript</div>
</div>
我在演示中使用ChromeVox屏幕阅读器;市面上有很多屏幕阅读器,其中一些将在本文末尾提供链接。
在每个元素上使用role可能很诱人,但正如我之前提到的,强烈建议使用具有正确语义的原生元素来构建列表(因为能力越大,责任越大)。话虽如此,但由于原生元素具有隐式语义,因此不应在原生元素上使用 role。例如,ol或ul标签不需要具有role=list属性,同样,li标签也不需要具有role=listitem。
React 中的可访问列表
但是 ARIA 属性如何与 React 应用程序相适应,更准确地说是与 JSX 相适应?
JSX编译为 HTML,由于方法无效,JSX 可能会编译为非语义 HTML,我们都知道屏幕阅读器很难解释它。这最终会导致无法访问的 Web 应用程序。
例如:
render() {
return (
<div>
{this.state.frameworks.map(f => <li>{f}</li>)}
<li> Ember </li>
</div>
)
}
编写这样的 JSX 将导致非语义化的 HTML。上述代码在编译时将产生以下结果:
<ol>
...
<div>
<li>...</li>
<li> Ember </li>
</div>
</ol>
在这种情况下,屏幕阅读器不会宣布列表,只会列出单个列表项,这可能会让最终用户感到困惑。
包装组件子项的正确方法是使用 React Fragments。
反应片段
“React 中的一个常见模式是让一个组件返回多个元素。Fragment 可让您对子项列表进行分组,而无需向 DOM 添加额外的节点。”
使用<React.Fragment>组件,我们可以向 JSX 元素添加父元素,而无需在 DOM(文档对象模型)中引入额外的节点,这意味着<React.Fragment>不会输出任何 HTML 元素。
React Fragment 还有一个简写版本 - <>...</>
完整代码
import React, { Component } from "react";
import ReactDOM from "react-dom";
class JSFrameworks extends Component {
constructor(props) {
super(props);
this.state = {
frameworks: ['React', 'Angular', 'Vue']
}
}
render() {
return (
<>
{this.state.frameworks.map(f => <li>{f}</li>)}
<li>Ember</li>
</>
)
}
}
class App extends Component {
constructor(props) {
super(props);
this.state = {
listItems: ['HTML', 'CSS', 'JavaScript']
};
}
render() {
return (
<div className="App">
<h1> Inaccessible Lists </h1>
<ol>
{this.state.listItems.map(item => <li>{item}</li>)}
<ol type='i'>
<JSFrameworks />
</ol>
</ol>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
React 应用中使用 ARIA
React 完全支持在 JSX 中使用 ARIA-* 属性。在 ARIA 的情况下,我们不需要将属性名称采用驼峰式命名(即使 React 害怕与 ARIA 混淆 - 抱歉,我保证不会再拿 Arya 开玩笑了)。
render() {
return (
<div role="list">
<div role="listitem"><span aria-label="1"></span> HTML</div>
<div role="listitem"><span aria-label="2"></span> CSS</div>
<div role="listitem"><span aria-label="3"></span> JavaScript</div>
</div>
);
}
结论
我希望您现在已经认识到构建可访问的 Web 应用程序的重要性,并可以从本指南中吸取一些经验。现在,离开这里并开始构建东西。干杯,祝您编码愉快。
热门屏幕阅读器
参考
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~