
本文详解移动导航按钮与菜单的 ARIA 属性规范,包括 aria-expanded 的合法取值、aria-label 的语义化写法、aria-controls 与 aria-hidden 的配合逻辑,并指出常见误用(如用 "Open menu" 作为 label、错误赋值 aria-expanded="active")及修复方案。
本文详解移动导航按钮与菜单的 aria 属性规范,包括 `aria-expanded` 的合法取值、`aria-label` 的语义化写法、`aria-controls` 与 `aria-hidden` 的配合逻辑,并指出常见误用(如用 "open menu" 作为 label、错误赋值 `aria-expanded="active"`)及修复方案。
构建具备无障碍支持的移动端导航菜单,不能仅依赖视觉状态,而需通过语义化 ARIA 属性向辅助技术(如屏幕阅读器)准确传达组件功能与当前状态。以下是经过 WCAG 2.1 和 ARIA Authoring Practices 指南验证的最佳实践:
✅ 正确设置 aria-expanded
aria-expanded 是一个布尔型状态属性,其合法值仅有三个:true、false 或省略(即未定义,默认为 false)。它不可接受字符串如 "active"、"open" 或 JavaScript 变量名。
✅ 正确用法(Vue 示例):
<button :aria-expanded="active" aria-controls="menu" aria-label="Main navigation" > <span class="hamburger-icon"></span> </button>
其中 active 应为布尔值(true 表示菜单已展开,false 表示收起)。当菜单打开时,aria-expanded="true" 向屏幕阅读器明确宣告“该控件所控制的区域当前处于展开状态”。
❌ 错误示例:
<!-- ❌ 无效值,将被忽略或导致不可预测行为 --> <button aria-expanded="active">...</button>
✅ 语义化 aria-label:描述内容,而非操作
aria-label 的核心作用是为无文本内容的控件提供可理解的名称(name),而非说明用户“该做什么”。因此:
- ❌
"Open menu"/"Close menu"是冗余且不推荐的——因为aria-expanded已隐式表达开闭状态,且按钮本身的操作(点击)由辅助技术自动播报; - ✅ 推荐使用描述性名称,如
"Main navigation"、"Site navigation"或"Primary menu",使用户清楚知道这个按钮控制的是哪一部分内容。
同理,关闭按钮(X)应标注其所代表的内容本质,而非动作:
<!-- ✅ 清晰、简洁、语义正确 --> <button aria-label="Main navigation" @click="closeMenu"> <span aria-hidden="true">×</span> </button>
? 提示:内部
×符号应添加aria-hidden="true",避免被屏幕阅读器重复朗读。
✅ aria-controls 与 aria-hidden 的协同逻辑
-
aria-controls="menu"必须与目标元素的id="menu"严格匹配,建立明确的“控制关系”; - 菜单容器应同时设置:
<nav id="menu" :aria-hidden="!active"> <!-- 导航链接 --> </nav>
当
active === true时,aria-hidden="false"(显式声明)虽非必需,但显式设为false可增强兼容性;更推荐直接省略该属性(默认即为false),仅在隐藏时设aria-hidden="true":<nav id="menu" :aria-hidden="!active ? 'true' : undefined">
❌ 关于关闭按钮是否需要 aria-expanded 和 aria-controls?
不需要。原因如下:
-
aria-expanded仅适用于可展开/折叠的控件本身(如汉堡按钮),用于指示其控制区域的状态; - 关闭按钮(X)是菜单内部的操作控件,不“控制”菜单的展开状态,而是触发状态变更——其角色更接近“取消”或“关闭”,应通过
aria-label明确其归属(如"Main navigation"),而非重复声明状态; -
aria-controls也无需添加,因为它并不控制外部元素,而是与父级菜单共处同一上下文。
✅ 完整可访问代码结构(Vue + HTML)
<!-- 汉堡按钮 -->
<button
@click="toggleMenu"
:aria-expanded="active"
aria-controls="menu"
aria-label="Main navigation"
>
<span class="hamburger-icon" aria-hidden="true">☰</span>
</button>
<!-- 导航菜单 -->
<nav id="menu" :aria-hidden="!active ? 'true' : undefined">
<div class="menu-header">
<!-- 关闭按钮:语义归属清晰,不加 aria-expanded -->
<button @click="closeMenu" aria-label="Main navigation">
<span aria-hidden="true">×</span>
</button>
</div>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>⚠️ 注意事项总结
- 始终确保
aria-expanded绑定布尔值,避免字符串误用; -
aria-label优先描述“是什么”,而非“做什么”; -
aria-controls与id必须一一对应,且目标元素应为可聚焦/可读的流内容容器(如<nav></nav>、<div role="region">);<li>对纯装饰性图标(如 <code>☰、×)务必添加aria-hidden="true"; - 测试建议:使用 NVDA + Firefox 或 VoiceOver + Safari 手动切换菜单,确认播报内容为 “Main navigation, button, expanded” / “Main navigation, button, collapsed”。
遵循以上规范,你的移动导航不仅视觉可用,更能真正实现「对所有人可用」(usable by everyone)的无障碍设计目标。

















