Javascript 键盘a11y,用于多级导航菜单,按钮为顶级项

Javascript 键盘a11y,用于多级导航菜单,按钮为顶级项,javascript,html,accessibility,Javascript,Html,Accessibility,我有一个元素有两个级别。顶级项用标记标记,子项用标记标记,例如: <nav role="navigation"> <ul> <li> <button type="button">Category 1</button> <ul class="submenu"> <li>

我有一个元素有两个级别。顶级项用标记标记,子项用标记标记,例如:

<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

当顶级项目标记聚焦时打开菜单。 在用户通过子项进行选项卡操作时,保持菜单打开。 当焦点移动到另一个顶级项目或页面的其余部分时,关闭菜单。 此外,允许通过Escape键关闭菜单并转移焦点

选择2

使用role=菜单将获得的焦点语义,即: 输入,空格键或向下箭头键打开顶层项目菜单; 子项上的向下箭头将焦点移动到下一项; 子项上的向上箭头将焦点移动到上一项; 顶层项目上的向上箭头关闭菜单,然后; 在子项上按Escape键时,关闭菜单并将焦点转移到顶级项

这将允许保留Tab键以移动到下一个顶级项目


就我个人而言,我更喜欢选项2,但我确实想知道它是否模糊了预期内容和显示内容之间的界限。

选项2最初感觉像右键盘语义,但这种行为应该保留给经典意义上的真正菜单。也就是说,菜单,如文件、编辑、查看。。。下面列出了即时操作,例如文件>打开或编辑>首选项。选项2还意味着您的菜单必须是一个制表位,用户将使用左/右箭头从类别1移动到类别2。我想你不想那样

对于导航菜单,它们不是经典意义上的菜单。它们只是一组链接列表,用于导航到其他页面

有一个关于W3C-菜单的优秀教程。该教程中有一节介绍了经典菜单,如上面提到的“文件”、“编辑”、“视图”

我几乎总是建议使用按钮进行即时操作,并使用链接导航到另一个页面,但对于导航菜单,经常使用链接,即使它们仅控制其他菜单项的下拉列表,这通常是按钮的工作。是否为顶级项目使用按钮或链接取决于您。就我个人而言,我会使用链接,以便所有元素都是链接,但这只是个人偏好

在任何情况下,无论您使用按钮还是顶级项的链接,元素最初都应该设置为false。当用户选择顶级链接时,将aria expanded更改为true

以下是我期望的键盘行为:

我应该能够跨顶级项目进行制表。从类别1到类别2的选项卡。顶层项目的视觉外观应该有一个向下的三角形或一些图标,指示该菜单中有某些内容。当顶级项目收到焦点时,不要打开子菜单。这使得键盘用户很难进入最后一个顶级项目,因为他们必须浏览每个子菜单。 当我在顶层项目上单击tab键时,我应该能够按enter键展开下拉菜单。焦点不应移动到第一个子菜单项。它应该保留在顶级项目上。按tab键将进入第一个子菜单项。如果DOM的子菜单项紧跟在顶级项之后,您将免费获得这种选项卡行为。您的示例代码就是一个很好的示例。然后,我可以通过选项卡浏览所有子菜单项。 如果在对子菜单进行Tab切换时按esc键,子菜单应关闭,焦点应移到打开子菜单的顶级项目,顶级项目的aria expanded应设置为false。 如果我关闭最后一个子菜单项,子菜单应关闭,焦点应转到下一个顶级项,打开子菜单的顶级项应设置为false。 如果我在第一个子菜单项上按住shift+tab键,焦点自然会转到打开子菜单的顶级项。子菜单应仍然可见。如果我再次按住shift+tab键,则子菜单应关闭,焦点应转到上一个顶级项,并且对于打开子菜单的顶级项,aria expanded应设置为false。 一开始听起来有点复杂,但实际上相当简单和优雅。好的是,大部分的标签行为都是免费的。您只需实现enter来打开子菜单,esc来关闭子菜单,以及一些onblur处理程序来关闭子菜单

作为补充说明,您不必为已经分配了默认角色的本机html元素指定角色。比如说

<nav role="navigation">
应该是

<nav>
<button>Category 1</button>

应该是

<nav>
<button>Category 1</button>
html5规范 并向您显示默认角色,特别是

默认值-\u不设置_


此外,您还应该有一个or。这在上述教程的一节中提到。

感谢您提供非常详细的答案!关于你关于“我正在设置类型而不是角色”属性的说明,因为按钮的默认类型是“提交”,我想明确说明这是一个用户定义的按钮。啊,抱歉。我误解了。评论仍然适用:-