Joe*_*Joe 6 html accessibility wai-aria
我在可视化中有一个数据列表,我希望使其尽可能易于访问。有两个彼此相邻的列表。
列表项有两种状态。多行可以是活动的或非活动的。可以选择单行。
在一个列表中选择某项,会将“相关”项目显示为活动和非活动。请参阅下面的简化示例。用户选择了“A 2”,它链接到“B 1”和“B 4”,所以 A2 是,aria-selected但没有aria-activeor aria-inactive,我想按照演示使用aria-disabled- 但这是否表明它不可交互?用户仍然可以单击禁用的项目来选择它。
对单个“选定”项目执行多个aria-selected, 和单个操作会更好吗?aria-current=true如果用户尚未做出选择并且所有内容都处于“活动”状态,则每个项目都会处于“活动”状态,这会很奇怪吗aria-selected=true?
.container {
display: grid;
grid-template-columns: 200px 200px
}
.list div {
margin: 0.5rem;
background: grey;
}
.list .selected {
background: red;
}
.list .inactive {
opacity: 0.3;
}Run Code Online (Sandbox Code Playgroud)
<div class="container">
<div class="list">
<div role="row">A 1</div>
<div role="row" class="selected" aria-selected="true">A 2</div>
<div role="row">A 3</div>
<div role="row">A 4</div>
</div>
<div class="list">
<div role="row">B 1</div>
<div role="row" class="inactive" aria-disabled="true">B 2</div>
<div role="row" class="inactive" aria-disabled="true">B 3</div>
<div role="row">B 4</div>
</div>
</div>Run Code Online (Sandbox Code Playgroud)
评论的澄清。以下是所选项目的实际实现方式:
,它非常复杂,所以我尝试将其提炼为具体问题。
role="presentation". 实际上中间有一个时间线,并且只有当时间线中的项目共享其他列表中的项目时,事物才“活动”?我没有考虑过aria-label,我认为这可能是最好的解决方案,因为用户可以单击并选择非活动项目。
从语义和可访问性的角度来看,我会考虑将控件与可视化本身\xe2\x80\x94 分离,至少在标记方面。这将使您可以使用更多语义输入元素,例如<input type="radio">,它们具有辅助技术可以理解的自己的状态。并且它将保持选择状态(这是一个输入元素特征)与突出显示状态(这是一个可视化显示特征)分开。
然后,您可以使用以下方法将这些输入元素绑定到可视化:aria-controls。
为了表示可视化本身中项目的状态,我建议仅使用文本,而不是使用 ARIA 角色。
\n一个基本的例子可以像这样工作:
\nconst items = document.querySelectorAll(\'.item\')\ndocument.querySelectorAll(\'input\').forEach(input => {\n input.addEventListener(\'change\', e => {\n let targets = e.target.dataset.controls.split(\' \')\n items.forEach(item => {\n let index = targets.indexOf(item.id)\n if (-1 === index) item.dataset.state = \'inactive\'\n else if (0 === index) item.dataset.state = \'selected\'\n else item.dataset.state = \'highlighted\'\n })\n })\n})Run Code Online (Sandbox Code Playgroud)\r\nbody {\n display: grid;\n grid-template: auto auto / auto auto;\n grid-auto-flow: column;\n}\nform,\nfigure {\n display: grid;\n grid-template: auto/auto auto 1fr;\n gap: 1ch;\n}\nfieldset {\n display: grid;\n grid-template: auto/auto auto;\n}\ninput,\nlabel {\n cursor: pointer;\n}\nfigure,\nul {\n padding: 0;\n margin: 0;\n}\nul {\n list-style: none;\n}\nli {\n margin: 1ch 0 0 1ch;\n padding: 1ch;\n}\nli[data-state="inactive"] {\n background: #ddd;\n}\nli[data-state="selected"] {\n background: #aaffaa;\n}\nli[data-state="highlighted"] {\n background: #aaaaff;\n}\nli[data-state="inactive"] span,\nli[data-state="highlighted"] span.selected {\n display: none;\n}\nli[data-state="selected"] span,\nli[data-state="highlighted"] span.highlighted {\n display: inline;\n}Run Code Online (Sandbox Code Playgroud)\r\n<h2>Controls</h2>\n<form>\n <fieldset>\n <legend>List A</legend>\n <input id="input-A1" type="radio" name="input" aria-controls="graphic" data-controls="item-A1 item-B2 item-B3" />\n <label for="input-A1">A1</label>\n <input id="input-A2" type="radio" name="input" aria-controls="graphic" data-controls="item-A2 item-B1" />\n <label for="input-A2">A2</label>\n <input id="input-A3" type="radio" name="input" aria-controls="graphic" data-controls="item-A3 item-B2 item-B3 item-B4" />\n <label for="input-A3">A3</label>\n <input id="input-A4" type="radio" name="input" aria-controls="graphic" data-controls="item-A4 item-B2" />\n <label for="input-A4">A4</label>\n </fieldset>\n <fieldset>\n <legend>List B</legend>\n <input id="input-B1" type="radio" name="input" aria-controls="graphic" data-controls="item-B1 item-A2 item-A3 item-A4" />\n <label for="input-B1">B1</label>\n <input id="input-B2" type="radio" name="input" aria-controls="graphic" data-controls="item-B2 item-A2 item-B3" />\n <label for="input-B2">B2</label>\n <input id="input-B3" type="radio" name="input" aria-controls="graphic" data-controls="item-B3 item-A1 item-A4" />\n <label for="input-B3">B3</label>\n <input id="input-B4" type="radio" name="input" aria-controls="graphic" data-controls="item-B4 item-A2" />\n <label for="input-B4">B4</label>\n </fieldset>\n</form>\n<h2>Visualization</h2>\n<figure id="graphic" aria-live="polite">\n <ul aria-label="List A">\n <li class="item" id="item-A1" data-state="inactive">A1<span class="selected">, selected</span><span class="highlighted">, highlighted</span></li>\n <li class="item" id="item-A2" data-state="inactive">A2<span class="selected">, selected</span><span class="highlighted">, highlighted</span></li>\n <li class="item" id="item-A3" data-state="inactive">A3<span class="selected">, selected</span><span class="highlighted">, highlighted</span></li>\n <li class="item" id="item-A4" data-state="inactive">A4<span class="selected">, selected</span><span class="highlighted">, highlighted</span></li>\n </ul>\n <ul aria-label="List B">\n <li class="item" id="item-B1" data-state="inactive">B1<span class="selected">, selected</span><span class="highlighted">, highlighted</span></li>\n <li class="item" id="item-B2" data-state="inactive">B2<span class="selected">, selected</span><span class="highlighted">, highlighted</span></li>\n <li class="item" id="item-B3" data-state="inactive">B3<span class="selected">, selected</span><span class="highlighted">, highlighted</span></li>\n <li class="item" id="item-B4" data-state="inactive">B4<span class="selected">, selected</span><span class="highlighted">, highlighted</span></li>\n </ul>\n</figure>Run Code Online (Sandbox Code Playgroud)\r\n但您可能希望通过单击项目本身来直接操作可视化。如果是这样,您可以保持与第一个示例相同的结构,但在视觉上隐藏可访问的控件和文本,并在用户单击可视化中的项目时触发控件。
\n同样,这仍然有负责控制状态\xe2\x80\x94的表单控件,它们只是在视觉上隐藏:
\nconst items = document.querySelectorAll(\'.item\')\ndocument.querySelectorAll(\'input\').forEach(input => {\n input.addEventListener(\'change\', e => {\n let targets = e.target.dataset.controls.split(\' \')\n items.forEach(item => {\n let index = targets.indexOf(item.id)\n if (-1 === index) item.dataset.state = \'inactive\'\n else if (0 === index) item.dataset.state = \'selected\'\n else item.dataset.state = \'highlighted\'\n })\n })\n})\nitems.forEach(item => {\n item.addEventListener(\'click\', e => {\n let inputId = \'input-\' + e.target.id.split(\'-\')[1]\n document.getElementById(inputId).click()\n })\n})Run Code Online (Sandbox Code Playgroud)\r\n.sr-only {\n border: 0;\n clip: rect(1px, 1px, 1px, 1px);\n -webkit-clip-path: inset(50%);\n clip-path: inset(50%);\n height: 1px;\n margin: -1px;\n overflow: hidden;\n padding: 0;\n position: absolute;\n width: 1px;\n white-space: nowrap;\n}\nfigure {\n display: grid;\n grid-template: auto/auto auto 1fr;\n gap: 1ch;\n}\nfigure,\nul {\n padding: 0;\n margin: 0;\n}\nul {\n list-style: none;\n}\nli {\n margin: 1ch 0 0 1ch;\n padding: 1ch;\n cursor: pointer;\n}\nli:hover {\n opacity: 0.6;\n}\nli[data-state="inactive"] {\n background: #ddd;\n}\nli[data-state="selected"] {\n background: #aaffaa;\n}\nli[data-state="highlighted"] {\n background: #aaaaff;\n}\nli[data-state="inactive"] span,\nli[data-state="highlighted"] span.selected {\n display: none;\n}\nli[data-state="selected"] span,\nli[data-state="highlighted"] span.highlighted {\n display: inline;\n}Run Code Online (Sandbox Code Playgroud)\r\n<div class="sr-only">\n <h2>Controls</h2>\n <form>\n <fieldset>\n <legend>List A</legend>\n <input id="input-A1" type="radio" name="input" aria-controls="graphic" data-controls="item-A1 item-B2 item-B3"/>\n <label for="input-A1">A1</label>\n <input id="input-A2" type="radio" name="input" aria-controls="graphic" data-controls="item-A2 item-B1"/>\n <label for="input-A2">A2</label>\n <input id="input-A3" type="radio" name="input" aria-controls="graphic" data-controls="item-A3 item-B2 item-B3 item-B4"/>\n <label for="input-A3">A3</label>\n <input id="input-A4" type="radio" name="input" aria-controls="graphic" data-controls="item-A4 item-B2"/>\n <label for="input-A4">A4</label>\n </fieldset>\n <fieldset>\n <legend>List B</legend>\n <input id="input-B1" type="radio" name="input" aria-controls="graphic" data-controls="item-B1 item-A2 item-A3 item-A4"/>\n <label for="input-B1">B1</label>\n <input id="input-B2" type="radio" name="input" aria-controls="graphic" data-controls="item-B2 item-A2 item-B3"/>\n <label for="input-B2">B2</label>\n <input id="input-B3" type="radio" name="input" aria-controls="graphic" data-controls="item-B3 item-A1 item-A4"/>\n <label for="input-B3">B3</label>\n <input id="input-B4" type="radio" name="input" aria-controls="graphic" data-controls="item-B4 item-A2"/>\n <label for="input-B4">B4</label>\n </fieldset>\n </form>\n</div>\n<h2 class="sr-only">Visualization</h2>\n<figure id="graphic" aria-live="polite">\n <ul aria-label="List A">\n <li class="item" id="item-A1" data-state="inactive">A1<span class="sr-only selected">, selected</span><span class="sr-only highlighted">, highlighted</span></li>\n <li class="item" id="item-A2" data-state="inactive">A2<span class="sr-only selected">, selected</span><span class="sr-only highlighted">, highlighted</span></li>\n <li class="item" id="item-A3" data-state="inactive">A3<span class="sr-only selected">, selected</span><span class="sr-only highlighted">, highlighted</span></li>\n <li class="item" id="item-A4" data-state="inactive">A4<span class="sr-only selected">, selected</span><span class="sr-only highlighted">, highlighted</span></li>\n </ul>\n <ul aria-label="List B">\n <li class="item" id="item-B1" data-state="inactive">B1<span class="sr-only selected">, selected</span><span class="sr-only highlighted">, highlighted</span></li>\n <li class="item" id="item-B2" data-state="inactive">B2<span class="sr-only selected">, selected</span><span class="sr-only highlighted">, highlighted</span></li>\n <li class="item" id="item-B3" data-state="inactive">B3<span class="sr-only selected">, selected</span><span class="sr-only highlighted">, highlighted</span></li>\n <li class="item" id="item-B4" data-state="inactive">B4<span class="sr-only selected">, selected</span><span class="sr-only highlighted">, highlighted</span></li>\n </ul>\n</figure>Run Code Online (Sandbox Code Playgroud)\r\n