如何实现HTML嵌套多级下拉菜单并采用hover效果展开?
- 内容介绍
- 文章标签
- 相关推荐
本文共计421个文字,预计阅读时间需要2分钟。
多级下拉菜单的可访问性和CSS控制依赖于标准列表语义。浏览器默认支持ul和li的缩进、焦点流、屏幕阅读器播报等功能。使用div模拟菜单会导致键盘导航失效、Tab键跳转错乱,且在移动端:hover状态无意义,降低可访问性。
document.querySelectorAll('nav li.has-submenu > a').forEach(el => { el.addEventListener('click', e => { e.preventDefault(); const parentLi = el.parentElement; parentLi.classList.toggle('submenu-open'); }); });
对应CSS只需监听.submenu-open > ul而非:hover,并确保has-submenu类已静态写入HTML。
注意:e.preventDefault()必须加,否则页面会跳转;同时要避免在桌面端重复绑定导致双击才展开。
键盘导航和焦点管理不能靠CSS解决
仅靠:hover和display: block会让Tab键跳过所有子菜单项,用户无法用键盘操作二级选项。这是WCAG 2.1 2.1.1关键失败点。
必须配合以下动作:
- 子
ul默认设visibility: hidden; position: absolute;,而非display: none(后者会从焦点流中彻底移除) - 用
tabindex="-1"手动控制子菜单项的可聚焦性,在展开时动态设tabindex="0",收起时重置 - 监听
ArrowDown/ArrowUp在同级菜单间切换,Escape收起当前展开项
最易被忽略的是:当子菜单展开后,焦点仍停留在父链接上,用户按Tab会跳到下一个顶级项,而不是第一个子项——这需要JS主动focus()到子菜单首个a。
本文共计421个文字,预计阅读时间需要2分钟。
多级下拉菜单的可访问性和CSS控制依赖于标准列表语义。浏览器默认支持ul和li的缩进、焦点流、屏幕阅读器播报等功能。使用div模拟菜单会导致键盘导航失效、Tab键跳转错乱,且在移动端:hover状态无意义,降低可访问性。
document.querySelectorAll('nav li.has-submenu > a').forEach(el => { el.addEventListener('click', e => { e.preventDefault(); const parentLi = el.parentElement; parentLi.classList.toggle('submenu-open'); }); });
对应CSS只需监听.submenu-open > ul而非:hover,并确保has-submenu类已静态写入HTML。
注意:e.preventDefault()必须加,否则页面会跳转;同时要避免在桌面端重复绑定导致双击才展开。
键盘导航和焦点管理不能靠CSS解决
仅靠:hover和display: block会让Tab键跳过所有子菜单项,用户无法用键盘操作二级选项。这是WCAG 2.1 2.1.1关键失败点。
必须配合以下动作:
- 子
ul默认设visibility: hidden; position: absolute;,而非display: none(后者会从焦点流中彻底移除) - 用
tabindex="-1"手动控制子菜单项的可聚焦性,在展开时动态设tabindex="0",收起时重置 - 监听
ArrowDown/ArrowUp在同级菜单间切换,Escape收起当前展开项
最易被忽略的是:当子菜单展开后,焦点仍停留在父链接上,用户按Tab会跳到下一个顶级项,而不是第一个子项——这需要JS主动focus()到子菜单首个a。

