纯CSS无JS实现导航子菜单 鼠标移出父链接子菜单消失问题
问题根因
子菜单一移开父链接就消失,核心是两个问题:
- 你写的显示触发规则只有「鼠标悬停在父级a链接上」这一个条件,鼠标一旦离开a标签的范围,不管是不是往子菜单方向移动,子菜单都会立刻隐藏。
- 父链接和子菜单之间留了空隙,鼠标从链接往下移动到子菜单的过程中,会经过一段没有任何元素的空白区域,直接丢失hover状态。
之前改top值、z-index没效果,是因为根本没改触发逻辑,只调整位置和层级解决不了状态判定的问题。
修复步骤
- 调整定位基准:之前你给
#header__link-resources这个a标签加了相对定位,但子菜单是和a标签同级、放在li标签下的元素,定位基准错了很容易出现偏移。把相对定位加到包含下拉菜单的父级li标签上,让子菜单相对于整个导航项定位。 - 修改hover触发范围:不要把触发条件绑在单独的a标签上,改成绑定整个父级li标签——只要鼠标在li的范围内(不管是悬停在顶部的导航链接上,还是已经移到下面展开的子菜单上),都保持子菜单显示。
- 消除触发间隙:子菜单的top值不要写死固定像素留空,改成
top:100%让它紧贴导航项底部,如果需要视觉上的间距,用子菜单的padding-top实现,不要留无元素的空白间隙,避免鼠标移动时中断hover状态。
具体修改代码
首先调整定位相关的CSS,删掉原来给a标签加的相对定位,换成给父级li加:
/* 删除原有代码 #header__link-resources{ position: relative; } */ /* 新增:给带子菜单的导航项加相对定位,作为子菜单的定位基准 */ .header__item:has(.header__submenu) { position: relative; }
然后替换原来的hover显示规则,把触发对象改成父级li,同时保留子菜单自身的hover显示状态:
/* 删除原有绑定在a标签上的hover代码 #header__link-resources:hover ~ #header__submenu-resources{ opacity: 1; visibility: visible; display: block; } #header__link-company:hover ~ #header__submenu-company{ opacity: 1; visibility: visible; display: block; } */ /* 新增:整个导航项hover、或者子菜单自身hover时都保持显示 */ .header__item:has(.header__submenu):hover .header__submenu, .header__submenu:hover { opacity: 1; visibility: visible; display: block; z-index: 99; }
最后调整子菜单的位置属性,消除间隙:
.header__submenu{ position: absolute; right: 0; /* 替换原来的top: 60px,紧贴导航项底部 */ top: 100%; /* 用内边距做视觉间距,不会中断hover */ padding-top: 8px; width: 100%; visibility: hidden; opacity: 0; z-index: -1; transition: all .1s linear; -webkit-box-shadow: 0px 27px 25px -25px rgba(34, 60, 80, 0.2); -moz-box-shadow: 0px 27px 25px -25px rgba(34, 60, 80, 0.2); box-shadow: 0px 27px 25px -25px rgba(34, 60, 80, 0.2); }
如果要兼容不支持:has()选择器的旧浏览器,不用写JS,直接给带子菜单的li加个自定义类比如header__item--dropdown,把上面代码里的:has(.header__submenu)替换成这个类名就行。
内容的提问来源于stack exchange,提问作者Flain
相关产品推荐
相关产品推荐

