HTML多级子菜单需用ul/li合法嵌套,子菜单必须为父li直接子元素;添加ARIA属性(如role="menubar"、aria-haspopup)保障可访问性;CSS用li:hover ul定位并控制显隐;需兼容键盘与移动端,补充:focus-within或JS切换状态。

HTML列表标签实现多级子菜单,核心是用 ul 和 li 的合法嵌套结构——子菜单必须是父级 li 的直接子元素,不能外置、不能用 div 替代,否则会破坏语义、键盘导航和屏幕阅读器支持。
嵌套结构必须严格遵循父子关系
每个可展开的菜单项是一个 li,它的子菜单(下一级)必须写在这个 li 标签内部,作为其最后一个子节点:
- 产品
- Web
- Mobile
- 服务
- 咨询
- 实施
错误写法:把子 ul 放在父 li 外面,或塞进同级 div;这样 DOM 层级断裂,CSS li:hover ul 选不到,JS 也找不到父容器。
必须添加语义化 ARIA 属性
仅靠结构不够,还需辅助技术识别层级和状态:
立即学习“前端免费学习笔记(深入)”;
- 最外层 ul 加 role="menubar"
- 每个菜单项加 role="menuitem"
- 有子菜单的项加 aria-haspopup="true" 和 aria-expanded="false"
- 子菜单 ul 加 role="menu" 和 aria-labelledby 指向父项 ID
CSS 控制显示与定位的关键点
纯 CSS 实现 hover 展开时,三个细节决定成败:
- 用后代选择器 li:hover ul(空格),不是子代选择器 li:hover > ul,否则三级以后不响应
- 所有子菜单默认隐藏:ul ul { display: none; };悬停时统一显示:li:hover ul { display: block; }
- 父 li 设 position: relative,子 ul 用 position: absolute 定位,顶部紧贴父项底部,避免鼠标移入途中断 hover
移动端和键盘用户不能只靠 hover
:hover 在触屏设备上基本无效,且键盘用户无法用 Tab 进入子项。因此需补充:
- 用 :focus-within(现代浏览器)或 JS 切换 aria-expanded 和类名控制显隐
- 为可展开项绑定 Enter / Space 键事件,手动切换展开状态
- 子菜单隐藏时用 aria-hidden="true",而非仅靠 display: none



















