javascript - 用于将按钮作为顶级项目的多级导航菜单的键盘 a11y
问题描述
我有一个<nav>
有 2 个级别的元素。顶级<button>
项目用标签标记,子项目用<a>
标签标记,例如:
<nav role="navigation">
<ul>
<li>
<button type="button">Category 1</button>
<ul class="submenu">
<li>
<a href="/cat1/subcat1">Subcategory 1</a>
</li>
<!-- ... other links -->
</ul> <!-- /.submenu -->
</li>
<li>
<button type="button">Category 2</button>
<ul class="submenu">
<li>
<a href="/cat2/subcat1">Subcategory 1</a>
</li>
<!-- ... other links -->
</ul> <!-- /.submenu -->
</li>
</ul>
</nav>
顶级项目仅用作容器,没有自己的页面可链接。
我应该如何为此标记添加键盘可访问性?
我目前考虑的选项是:
选项1
当顶级项目(<button>
标签)被聚焦时打开菜单。
当用户在子项之间切换时,保持菜单打开。
当焦点移动到另一个顶级项目或页面的其余部分时关闭菜单。
此外,允许通过 Escape 键关闭菜单并转移焦点。
选项 2
使用 arole="menu"
将获得的焦点语义,即:
顶级项上的 Enter、Space 或向下箭头打开菜单;
子项上的向下箭头将焦点移至下一项;
子项上的向上箭头将焦点移至前一项;
顶级项目上的向上箭头关闭菜单,并且;
子项上的退出键,关闭菜单并将焦点转移到顶级项。
这将允许保留 Tab 键以移动到下一个顶级项目。
就个人而言,我更喜欢选项 2,但我想知道它是否模糊了预期和显示之间的界限。
解决方案
选项 2 最初感觉像是正确的键盘语义,但这种行为应该保留给经典意义上的“真正”菜单。也就是说,诸如“文件、编辑、查看...”之类的菜单下列出了即时操作(例如文件 > 打开或编辑 > 首选项)。选项 2 还意味着您的菜单必须是一个制表位,并且用户将使用左/右箭头从“类别 1”移动到“类别 2”。我不认为你想要那个。
对于导航“菜单”,它们并不是经典意义上的真正菜单。它们只是用于导航到其他页面的链接的分组列表。
W3C 上有一个关于菜单的优秀教程 - https://www.w3.org/WAI/tutorials/menus/。(该教程中有一个关于“应用程序菜单”的部分讨论了“经典”菜单,例如“文件、编辑、查看”,如上所述。)
我几乎总是建议使用按钮进行即时操作,使用链接导航到另一个页面,但是对于导航菜单,即使它们只控制更多菜单项的下拉列表(通常是按钮的工作),也经常使用链接。是否为顶级项目使用按钮或链接取决于您。就个人而言,我会使用链接,以便链接中的所有元素<nav>
都是链接,但这只是个人喜好。
在任何情况下,无论您对顶级项目使用按钮还是链接,该元素aria-expanded
最初都应该设置为“false”。当用户选择顶级链接时,更改aria-expanded
为“true”。
这是我期望的键盘行为:
- 我应该能够tab跨越顶级项目。从“类别 1”到“类别 2”的选项卡。(顶级项目的视觉外观应该有一个“向下三角形”或一些图标,表明该菜单中有一些东西。)当顶级项目获得焦点时,不要打开子菜单。这使得键盘用户很难到达最后一个顶级项目,因为他们必须浏览每个子菜单。
- 当我浏览顶级项目时,我应该能够点击enter展开下拉菜单。焦点不应移动到第一个子菜单项。它应该保留在顶级项目上。按tab应该带我到第一个子菜单项。(如果您的 DOM 在顶级项目之后立即有子菜单项,您将“免费”获得这种选项卡行为。您的示例代码就是一个很好的例子。)然后我可以通过所有子菜单项进行选项卡。
- 如果我在子菜单中切换时按下esc,子菜单应该关闭,并且焦点应该移动到打开子菜单的顶级项目(并且
aria-expanded
应该将顶级项目设置为“false”)。 - 如果我tab关闭了最后一个子菜单项,子菜单应该关闭并且焦点应该转到下一个顶级项目(并且
aria-expanded
应该为打开子菜单的顶级项目设置为“false”)。 - 如果 I shift+ taboff 第一个子菜单项,焦点自然应该转到打开子菜单的顶级项。子菜单仍应保持可见。如果 I shift+tab再次,则子菜单应该关闭并且焦点应该转到上一个顶级项目(并且
aria-expanded
应该为打开子菜单的顶级项目设置为“false”)。
起初听起来有点复杂,但实际上非常简单和优雅。好消息是您将免费获得大部分的标签行为。你只需要实现enter打开子菜单、esc关闭子菜单和一些 onblur() 处理程序来关闭子菜单。
作为旁注,您不必role
为已分配默认角色的本机 html 元素指定 a 。例如
<nav role="navigation">
应该只是
<nav>
和
<button type="button">Category 1</button>
应该只是
<button>Category 1</button>
html5 规范向您展示了默认角色,并特别<nav>
说明<button>
(默认 - _不设置_)
(此外,您<nav>
还应该有一个aria-label
or aria-labelledby
。这在上面提到的教程的“标签菜单”部分中提到。)
推荐阅读
- python - 在 python 中实现 SVM One-vs-all 时出现问题
- go - 如何阅读 http2 伪字段
- java - 从edittext中的任何位置删除最后添加的字符
- javascript - 是否可以制作一个自动将文本颜色更改为背景对比度的Javascript程序?
- javascript - 使用 JavaScript 而不是 jQuery 在按钮单击时滚动屏幕的顶部/底部 它应该在 chrome、IE 和 mozilla 中工作
- extendscript - 我们如何在不打开 After Effects 实例的情况下通过 Extendscript 更改 After Effects 项目层的文本?
- c# - 从 Json 数组访问属性
- html - 记住返回页面上的手风琴状态
- c# - 调整图像大小以填充 80x80 框 magick.net
- python - 向 PySpark 中的每一行添加不同的列计数