纯css下拉菜单必须采用嵌套html结构,子菜单需直接嵌套在父内,通过:hover触发显示;推荐使用position: absolute + opacity/visibility过渡实现淡入效果,并需js支持移动端点击切换及z-index、可访问性等细节优化。

下拉菜单的HTML结构必须是嵌套的和-
纯CSS下拉菜单依赖父元素悬停触发子菜单显示,所以结构不能是平级div拼接,必须用语义化的嵌套列表。常见错误是把子菜单写成独立
:hover完全无法关联到它。
正确结构长这样:
- 外层
<ul></ul>是导航栏容器,每个<li>是一个导航项 - 带下拉的项需加
class="dropdown"(仅作标识,非必须) - 子菜单
<ul class="dropdown-menu"></ul>必须直接嵌套在父<li>内部
关键CSS:用:hover控制display或visibility
子菜单默认隐藏,鼠标悬停父<li>时才显示。这里有两个主流方案,选哪个取决于交互需求:
-
display: none→display: block:切换快、无过渡,但无法做淡入动画(display不可过渡) -
visibility: hidden→visibility: visible+opacity:配合transition能实现淡入/滑动,但元素仍占文档流(需额外position: absolute脱离)
推荐组合:
.dropdown-menu {
position: absolute;
top: 100%;
left: 0;
opacity: 0;
visibility: hidden;
transition: opacity 0.2s, visibility 0.2s;
}
.dropdown:hover .dropdown-menu {
opacity: 1;
visibility: visible;
}
注意top: 100%让子菜单紧贴父项底部,position: absolute避免影响其他导航项布局。
移动端适配::hover失效时得靠JavaScript补位
CSS纯下拉在触摸设备上基本不可用——因为没有:hover状态。iOS Safari、Android Chrome都只在点击后短暂触发:hover,且不支持悬停保持。
- 如果只支持桌面端,当前CSS方案足够
- 若需兼容手机,必须加JS监听
click,动态切换一个active类,再用.dropdown.active .dropdown-menu控制显示 - 别试图用
@media (hover: hover)自动降级——它在很多安卓浏览器里返回hover为真,实际却没hover能力
简单JS补位示例:
document.querySelectorAll('.dropdown').forEach(el => {
el.addEventListener('click', e => {
e.preventDefault();
el.classList.toggle('active');
});
});
对应CSS追加一行:.dropdown.active .dropdown-menu { opacity: 1; visibility: visible; }
容易被忽略的z-index和聚焦可访问性
下拉菜单常被后面的内容盖住,根本原因是没设z-index。但只设一个数字不够——要确保它比所有同级容器高,且父容器不能是position: relative但z-index: 0这种“创建新层叠上下文却压低层级”的陷阱。
- 给
.dropdown设position: relative,给.dropdown-menu设z-index: 1000(数值够大即可) - 键盘用户需要按
Tab进入下拉项,所以子菜单<a></a>必须可聚焦,且初始tabindex="-1"在显示时改为0(否则隐藏状态下仍可Tab到不可见链接) - 用
aria-haspopup="true"和aria-expanded="false"标注状态,屏幕阅读器才懂这是下拉
真正上线时,光靠CSS实现的下拉菜单往往卡在这些细节上——视觉对了,但键盘操作断掉,或者在某个安卓WebView里永远不出现。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











