二级菜单不显示主因是定位链断裂,须给直接父元素设position: relative;悬停闪退需消除间隙或嵌套结构;移动端须用js切换class而非:hover;z-index失效常因父级创建新层叠上下文。

二级菜单不显示?检查 position 父子关系是否断裂
最常见的情况是:鼠标悬停时,.submenu 根本没出来,或者跑到了页面左上角。根本原因不是 CSS 写错了,而是定位链断了——.submenu 的父容器没设 position: relative,导致它用 position: absolute 时相对的是最近的「已定位祖先」,而不是你预期的菜单项。
- 必须给直接父元素(比如
.nav-item或li)加position: relative,否则absolute会一路往上找,常落到body或html上 - 不要在
.submenu上写top: 0; left: 0就完事,得结合父容器高度和 padding 调整,比如top: 100%才能紧贴父菜单下沿 - 如果父容器用了
display: flex但没设position: relative,同样失效——flex 不等于定位上下文
鼠标移开就闪退?别只靠 :hover 控制显隐
纯 CSS 下拉菜单最脆弱的点就是「悬停间隙」:从一级菜单移到二级菜单途中,鼠标经过空白区域,:hover 状态丢失,.submenu 立刻消失。这不是 bug,是预期行为。
- 在
.nav-item和.submenu之间留出垂直重叠区(比如用margin-bottom: -1px),让鼠标有“缓冲带”可滑过去 - 更稳妥的做法是把
.submenu直接嵌在.nav-item内部,并对整个.nav-item:hover .submenu触发显示,而非只对a:hover - 避免给
.submenu设opacity: 0+visibility: hidden后只靠transition显隐——过渡期间仍可能触发 hover 中断
移动端点击不展开?:hover 在触摸设备上基本不可靠
桌面端靠悬停,手机端没 hover。很多项目上线后才发现 iOS / Android 点击一级菜单毫无反应,因为 CSS 里只写了 :hover,没考虑点击态。
- 别指望
:hover在真机上稳定工作;iOS Safari 对 hover 支持极弱,Android Chrome 也仅在模拟器中有效 - 必须配合 JS 切换一个 class(如
is-open),用.nav-item.is-open .submenu控制显示,再用click事件 toggle - 如果坚持纯 CSS,可用
input[type="checkbox"]+label模拟开关,但语义差、可访问性低,不推荐线上项目 - 注意
touchstart和click的 300ms 延迟问题,建议用fastclick或监听touchend
层级错乱或被遮挡?z-index 不是万能解药
二级菜单弹出来,却被轮播图、固定头部、模态框盖住,第一反应是加 z-index: 9999 ——但往往没用,甚至让问题更隐蔽。
立即学习“前端免费学习笔记(深入)”;
-
z-index只在同一个层叠上下文(stacking context)内生效;父容器若已有transform、opacity 、<code>will-change,就会创建新层叠上下文,把子元素的z-index锁死在内部 - 优先检查父级是否有
transform: translateZ(0)或filter,这些都会无意中创建层叠上下文 - 真正要提升层级,得在「共同祖先」上设
z-index,而不是无脑堆高子元素的值;比如整个导航栏外层.header的z-index必须高于.banner










