必须用nav包裹语义化ul/li嵌套结构,子ul须为父li直接子元素,缩进仅用padding-left,悬停用li:hover ul并兼顾focus-within或js切换aria状态。

用 ul 嵌套结构定义层级,别碰 select
原生 select 根本不支持多级——optgroup 只能平铺显示,无法 hover 展开、无法嵌套、屏幕阅读器读不出层级。必须用语义化列表:nav 包 ul,每个一级 li 里直接放文字 + 子 ul,子 ul 必须是该 li 的**直接子元素**,否则 CSS 选择器失效、键盘导航中断、ARIA 属性错位。
li:hover ul 控制显隐,但得避开三个坑
纯 CSS 实现可行,但容易闪退或失效,关键在三点:
-
li:hover ul必须用**后代选择器(空格)**,不能写成li:hover > ul,否则三级菜单不响应 - 所有下拉
ul初始设为ul ul { display: none; },再用li:hover ul { display: block; }统一触发 - 父
li要position: relative,子ul用position: absolute定位,且顶部必须紧贴父项底部,不能有 border/margin 间隙,否则鼠标一移就收
移动端和键盘用户不能只靠 :hover
iOS/Android 上 :hover 基本不可靠,Tab 键也进不去子菜单。必须补 JS:
- 给可展开的
li加aria-haspopup="true"和aria-expanded="false" - 点击时切换
aria-expanded值,并用 class 控制显隐(比如.is-open),避免仅依赖display - 监听
keydown,对 Enter/Space 做展开,方向键做焦点移动 - 子菜单加
role="menu",子项加role="menuitem",确保屏幕阅读器能识别
定位和层叠问题最容易被忽略
子菜单常被父容器裁剪或遮挡,不是样式没写对,而是布局陷阱:
- 父容器(比如
nav或外层div)不能设overflow: hidden或overflow: scroll -
z-index要设在position: relative的父li上,而不是子ul上,否则层级错乱 - 避免用
pointer-events: none隐藏菜单——它会让焦点丢失,键盘用户彻底卡死
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











