下拉菜单是网页交互中最常见的元素之一,无论是导航栏的“产品分类”,还是表单里的“选择城市”,一个流畅、美观的下拉菜单都能显著提升用户体验,我们从实际开发角度出发,用最简单的方式,教你如何设置三种不同类型的下拉菜单。
纯 CSS 实现(最轻量,适合鼠标悬停)

这是最简单的一种方式,无需任何 JavaScript,适合桌面端导航场景,核心思路是:让子菜单默认隐藏,父级菜单被 hover 时显示子菜单。
HTML 结构:
<nav class="menu">
<ul>
<li>
<a href="#">关于我们</a>
<ul class="dropdown">
<li><a href="#">公司简介</a></li>
<li><a href="#">团队介绍</a></li>
<li><a href="#">加入我们</a></li>
</ul>
</li>
<li><a href="#">新闻中心</a></li>
<li><a href="#">联系我们</a></li>
</ul>
</nav>
CSS 样式:
.menu ul {
list-style: none;
padding: 0;
margin: 0;
display: flex;
background: #333;
}
.menu > ul > li {
position: relative; /* 关键:让子菜单绝对定位时参考父级 */
padding: 12px 20px;
}
.menu a {
color: #fff;
text-decoration: none;
}
/* 隐藏子菜单 */
.dropdown {
display: none;
position: absolute;
top: 100%; /* 紧贴父级下方 */
left: 0;
background: #444;
min-width: 120px;
flex-direction: column;
}
/* 悬停时显示 */
.menu li:hover .dropdown {
display: flex;
}
.dropdown li {
padding: 10px 15px;
}
.dropdown li:hover {
background: #555;
}
要点:
position: relative放在父 li 上,绝对定位的子菜单才能对齐。top: 100%让子菜单位于父项正下方。- 只需要
hover即可,无需 JS。
局限: 无法在移动端触屏上使用,因为手机没有 hover 操作,适合 PC 端后台或简洁官网。
CSS + 点击展开(适合移动端适配)
如果你需要同时支持点击和悬停,可以用一个 <button> 或 <a> 配合 JavaScript 来切换类名,这里我们采用最常见的“点击按钮显示/隐藏”模式。
HTML 结构:
<div class="dropdown-wrapper">
<button class="dropdown-toggle">选择语言 ▾</button>
<ul class="dropdown-list" id="langList">
<li>中文</li>
<li>English</li>
<li>日本語</li>
</ul>
</div>
CSS 样式:
.dropdown-wrapper {
position: relative;
display: inline-block;
}
.dropdown-list {
display: none;
position: absolute;
top: 100%;
left: 0;
background: #fff;
border: 1px solid #ddd;
border-radius: 4px;
list-style: none;
padding: 0;
margin: 4px 0 0;
min-width: 120px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.dropdown-list li {
padding: 8px 16px;
cursor: pointer;
}
.dropdown-list li:hover {
background: #f5f5f5;
}
/* 当添加 .open 类时显示 */
.dropdown-wrapper.open .dropdown-list {
display: block;
}
JavaScript 代码(原生 JS):
const toggle = document.querySelector('.dropdown-toggle');
const wrapper = document.querySelector('.dropdown-wrapper');
toggle.addEventListener('click', function (e) {
e.stopPropagation(); // 防止事件冒泡到 document
wrapper.classList.toggle('open');
});
// 点击其他地方关闭下拉菜单
document.addEventListener('click', function (e) {
if (!wrapper.contains(e.target)) {
wrapper.classList.remove('open');
}
});
要点:
- 通过
.open类控制显示,比直接改 style 更利于维护。 stopPropagation()防止点击按钮时触发了 document 的关闭逻辑。- 点击任意空白处关闭,符合用户直觉。
纯 CSS 多级折叠菜单(适合侧边栏)
不需要点击,也不需要 hover,而是用 checkbox 黑客技巧实现纯 CSS 的展开/收起,适合做“手风琴”式侧边栏。
HTML 结构:
<div class="sidebar">
<label class="menu-item" for="sub1">📁 工程项目</label>
<input type="checkbox" id="sub1" class="submenu-trigger">
<ul class="submenu">
<li>立项管理</li>
<li>进度管理</li>
<li>成本控制</li>
</ul>
</div>
CSS 样式:
.submenu-trigger {
display: none; /* 隐藏 checkbox */
}
.submenu {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
list-style: none;
padding: 0;
margin: 0;
}
/* 当 checkbox 被选中时,相邻的 ul 展开 */
.submenu-trigger:checked + .submenu {
max-height: 200px; /* 根据内容调整 */
}
.menu-item {
display: block;
padding: 10px;
background: #f0f0f0;
cursor: pointer;
border-bottom: 1px solid #ddd;
}
要点:
- 原理是
checkbox的checked状态可以影响后续兄弟元素。 - 用
max-height做过渡动画,注意值要大于实际内容高度。 - 无需 JS,但每次只能控制自己的子菜单,不能互斥(除非配合额外的 radio)。
如何选择?
| 场景 | 推荐方案 |
|---|---|
| PC 端导航,鼠标悬停 | 方案一(纯 CSS hover) |
| 移动端或需要点击触发 | 方案二(JS 切换 class) |
| 侧边栏折叠菜单,无 JS 需求 | 方案三(checkbox hack) |
掌握了这三种思路,你基本可以应对绝大部分“设置下拉菜单”的需求,最后提醒一句:别忘了在移动端测试点击区域的大小,以及键盘操作(Tab 键)时的焦点管理,这对无障碍体验至关重要。

