【问题标题】:Keyboard a11y for a multi-level navigation menu with buttons as top level items用于将按钮作为顶级项目的多级导航菜单的键盘 a11y
【发布时间】:2019-05-29 23:50:49
【问题描述】:

我有一个有 2 个级别的 <nav> 元素。顶级项用<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

当顶级项目(&lt;button&gt; 标签)被聚焦时打开菜单。
当用户在子项之间切换时,使菜单保持打开状态。
当焦点移动到另一个顶级项目或页面的其余部分时关闭菜单。
此外,允许通过 Escape 键关闭菜单并转移焦点。

选项 2

使用role="menu" 将获得的焦点语义,即:
顶级项目上的 Enter、空格或向下箭头打开菜单;
子项上的向下箭头将焦点移至下一项;
子项上的向上箭头将焦点移至上一项;
顶级项目上的向上箭头关闭菜单,并且;
子项上的 Escape 键,关闭菜单并将焦点转移到顶级项。

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

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

【问题讨论】:

    标签: javascript html accessibility


    【解决方案1】:

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

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

    有一个关于 W3C 菜单的优秀教程 - https://www.w3.org/WAI/tutorials/menus/。 (该教程中有一个关于“application menus”的部分讨论了“经典”菜单,例如“文件、编辑、查看”,如上所述。)

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

    无论如何,无论您对顶级项目使用按钮还是链接,该元素最初都应将aria-expanded 设置为“false”。当用户选择顶级链接时,将aria-expanded更改为“true”。

    这是我期望的键盘行为:

    • 我应该能够跨顶级项目tab。从“类别 1”到“类别 2”的选项卡。 (顶级项目的视觉外观应该有一个“向下三角形”或一些图标,表明该菜​​单中有内容。)当顶级项目获得焦点时,不要不要打开子菜单。这使得键盘用户很难到达最后一个顶级项目,因为他们必须浏览每个子菜单。
    • 当我在顶级项目之间使用标签时,我应该能够点击 enter 来展开下拉菜单。焦点不应移动到第一个子菜单项。它应该保留在顶级项目上。按 tab 应该带我到第一个子菜单项。 (如果您的 DOM 在顶级项目之后立即包含子菜单项,您将“免费”获得这种选项卡行为。您的示例代码就是一个很好的例子。)然后我可以通过所有子菜单项进行选项卡。
    • 如果我在子菜单中切换时按 esc,子菜单应关闭,焦点应移至打开子菜单的顶级项目(aria-expanded 应设置为“false " 用于顶级项目)。
    • 如果我tab关闭最后一个子菜单项,子菜单应该关闭并且焦点应该转到下一个顶级项目(并且aria-expanded应该设置为“false”以获得顶级打开子菜单的项目)。
    • 如果我 shift+tab 关闭第一个子菜单项,焦点自然会转到打开子菜单的顶级项。子菜单仍应保持可见。如果我再次shift+tab然后子菜单应该关闭并且焦点应该转到上一个顶级项目(aria-expanded应该为打开子菜单的顶级项目设置为“false”)。

    起初听起来有点复杂,但实际上非常简单和优雅。好消息是您将免费获得大部分的标签行为。你只需要实现 enter 来打开子菜单, esc 来关闭子菜单,以及一些 onblur() 处理程序来关闭子菜单。

    附带说明,您不必为已分配默认角色的原生 html 元素指定 role。例如

    <nav role="navigation">
    

    应该是

    <nav>
    

    <button type="button">Category 1</button>
    

    应该是

    <button>Category 1</button>
    

    &lt;nav&gt;&lt;button&gt; 的 html5 规范向您展示了默认角色并特别说明了

    (默认 - _不设置_

    (另外,您的&lt;nav&gt; 还应该有一个aria-labelaria-labelledby。这在上面提到的教程的“Label menus”部分中提到。)

    【讨论】:

    • 感谢非常详细的回答!关于您关于&lt;button type="button"&gt; 的注释,我设置的是type 而不是role 属性,因为按钮的默认类型是提交,我想明确说明这是一个用户定义的按钮。
    • 啊,抱歉。我误读了。
    猜你喜欢
    • 2018-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-26
    • 1970-01-01
    • 1970-01-01
    • 2023-02-02
    相关资源
    最近更新 更多