纯CSS下拉菜单需子菜单为触发元素的直接后代或相邻兄弟,用li:hover .dropdown触发;推荐opacity:0+pointer-events:none+display:block实现动画与交互;须设父级position:relative、子级position:absolute并补间隙防闪退。

用 :hover 触发下拉菜单显示,但必须依赖结构嵌套
纯 CSS 实现下拉菜单的核心是:子菜单(通常是 <ul>)必须是触发元素(如 <li> 或 <a>)的**直接后代或相邻兄弟**,否则 :hover 无法穿透作用。常见错误是把下拉菜单写在导航外、用绝对定位脱离了父级流,却忘了在 CSS 中用父子选择器关联。
正确结构示例:
<nav>
<ul>
<li>
<a href="#">产品</a>
<ul class="dropdown">
<li><a href="/app">App</a></li>
<li><a href="/web">Web</a></li>
</ul>
</li>
</ul>
</nav>
-
.dropdown初始设为display: none或visibility: hidden - 悬停触发写成
li:hover .dropdown,不是a:hover .dropdown(因为<a>不包含下拉列表) - 若用
visibility,记得同时控制opacity和transition,否则隐藏时仍占布局空间
display: none 和 visibility: hidden 的行为差异直接影响交互体验
选错隐藏方式会导致鼠标移入失败、菜单闪退或无法点击。关键区别在于:display: none 元素完全不渲染,没有尺寸、不响应事件;visibility: hidden 仍占位,但鼠标无法穿透到其下的元素——这反而会断开悬停连续性。
- 推荐用
opacity: 0+pointer-events: none配合display: block切换,兼顾动画与可交互性 - 如果坚持用
display,过渡动画只能靠max-height模拟(设一个足够大的固定值,如max-height: 200px),并配overflow: hidden - 移动端 Safari 对
:hover支持不稳定,首次点击才激活 hover 状态,这不是 bug,是设计行为
下拉菜单定位失效?检查 position 上下文和 z-index 层级
菜单“飞走”或被遮挡,90% 是因为父容器没设 position: relative,导致 position: absolute 的下拉菜单相对于 body 定位。另一个常见问题是 z-index 没生效——它只对已定位元素(relative/absolute/fixed/sticky)起作用。
立即学习“前端免费学习笔记(深入)”;
- 必须给触发项的父级(如
li)加position: relative - 下拉菜单自身设
position: absolute,再用top、left微调位置 - 如果导航栏有
overflow: hidden,会裁剪出界的内容,需移除或改用clip-path替代 -
z-index值不需要很大,但要确保高于同层其他组件(比如轮播图、弹窗遮罩)
键盘用户和屏幕阅读器支持不能靠 CSS 单独解决
仅用 :hover 实现的下拉菜单,默认无法通过 Tab 键聚焦子项,也无法被读屏软件识别为可展开区域。这不是样式问题,而是语义缺失。
- 给触发链接加
aria-haspopup="true"和aria-expanded="false" - 用 JavaScript 监听
focus和keydown(如 Enter / ArrowDown),手动切换aria-expanded和菜单显隐 - CSS 可追加
&:focus-within .dropdown提供键盘焦点下的显示逻辑(但 IE 不支持,需降级) - 别忽略
Esc关闭菜单、Tab循环进入/退出的细节,这些才是真实可用性的分水岭
margin 负值或 top 微调补上,否则再好的 CSS 也白搭。


















