标准 · ARIA

角色 复合控件

menu

将容器标记为应用菜单 — 即「文件/编辑」风格菜单或上下文菜单的弹出层。没有对应的 HTML 等效元素。网站导航列表不是 menu;应使用包含链接 <ul> 的 <nav>。

何时使用

适用于应用风格的菜单 — 即从「文件」按钮弹出或通过右键点击触发的上下文菜单,支持方向键导航和按 Escape 关闭。子元素必须为 role="menuitem"role="menuitemcheckbox"role="menuitemradio"role="separator"

menu 角色属于应用语义。Web 上最常见的单一错误,就是将 role="menu" 用于网站导航 — 这会将键盘用户困在方向键导航中,错误地将链接宣告为菜单项,并破坏用户的心智模型。

经验法则:如果触发器是超链接且菜单项也是超链接,则它是导航,而非菜单。请使用 <nav><ul>

menu 必须具有可访问名称 — 使用 aria-labelaria-labelledby 指向触发元素。

键盘与焦点规范

根据 APG 菜单模式

  • 触发按钮具有 aria-haspopup="menu"aria-expanded。激活触发器会打开菜单并将焦点移至第一个 menuitem。
  • 菜单内部:上/下方向键在菜单项之间移动焦点;Home/End 跳转到第一个/最后一个菜单项。
  • 右方向键打开子菜单(如果聚焦项包含子菜单);左方向键返回父菜单。
  • Enter 或 Space 激活聚焦项并关闭菜单。
  • Escape 关闭菜单并将焦点返回触发器。
  • 首字母快速跳转:输入字母可跳转到以该字母开头的下一个菜单项。

单一制表位:同一时刻只有一个 menuitem 的 tabindex="0",其余均为 -1

常见错误

  • <nav> 元素上使用 role="menu"。应用语义会覆盖导航语义 — 屏幕阅读器不再将其宣告为导航地标。
  • 触发器上缺少与菜单配对的 aria-haspopup="menu"
  • Escape 关闭菜单后未将焦点返回触发器,导致用户迷失位置。
  • 菜单打开时焦点未移至第一个 menuitem — 用户不得不通过 Tab 键穿越空白区域。
  • 子菜单仅在悬停时打开,不支持键盘触发。

示例

<button id="actions" aria-haspopup="menu" aria-expanded="false" aria-controls="actionsMenu">
  Actions
</button>
<ul id="actionsMenu" role="menu" aria-labelledby="actions" hidden>
  <li role="menuitem" tabindex="0">Edit</li>
  <li role="menuitem" tabindex="-1">Duplicate</li>
  <li role="separator"></li>
  <li role="menuitem" tabindex="-1">Delete</li>
</ul>