纯CSS实现二级导航菜单需满足三条件:HTML中子ul必须为li的直接子元素、li设position:relative、用:hover>ul精准触发;移动端须弃用:hover,改用JS或checkbox模拟点击展开。

纯 CSS 实现二级导航菜单的关键在于结构语义正确、选择器精准、伪类触发时机合理——只要 <nav></nav> 嵌套层级清晰,:hover 作用域不越界,就能避免 JS 介入也能稳定展开子菜单。
HTML 结构必须用嵌套 <ul></ul> 而非 <div>
<p>二级菜单不是“在链接旁加个 <code><div class="submenu">”就能生效的。浏览器对 <code>:hover 的冒泡和作用范围有严格限制:只有后代元素在父级 hover 区域内才可被触发显示。若用 <div> 平级放置,<code>li:hover .submenu 根本选不到。
- ✅ 正确结构:每个顶级
<li> 内部直接包裹子 <ul></ul>,形成 DOM 层级嵌套
- ❌ 错误写法:
<li><a>服务</a></li>
<div class="submenu">...</div>(脱离父 <li>,hover 失效)
- ⚠️ 注意:子
<ul></ul> 必须是 <li> 的**直接子元素**,不能隔一层 <span></span> 或 <div>
<h3>
<code>:hover 显示子菜单时,display 和 visibility 的取舍
<li> 内部直接包裹子 <ul></ul>,形成 DOM 层级嵌套<li><a>服务</a></li>
<div class="submenu">...</div>(脱离父 <li>,hover 失效)<ul></ul> 必须是 <li> 的**直接子元素**,不能隔一层 <span></span> 或 <div>
<h3>
<code>:hover 显示子菜单时,display 和 visibility 的取舍用 display: none 隐藏子菜单最常见,但会导致布局重排(reflow),悬停瞬间有“跳动”;而 visibility: hidden 保留占位,视觉更稳,但需配合 opacity 和 pointer-events 才能真正禁用交互。
- ✅ 推荐组合:
visibility: hidden; opacity: 0; pointer-events: none;+transition: opacity .2s ease; - ❌ 单用
display: none:子菜单出现时宽度/高度从 0 计算,可能造成文字折行或图标错位 - ⚠️ 注意:若子菜单含表单控件(如搜索框),
pointer-events: none会禁用所有点击/聚焦,此时应改用opacity+transform: scaleY(0)控制显隐
响应式断点中,@media 下拉菜单需重置 hover 行为
小屏下通常切换为“点击展开”,但很多开发者只加了 @media (max-width: 768px) 的样式,却忘了关闭桌面端的 :hover 触发逻辑——结果是手指轻点一级菜单时,子菜单闪一下又收起,体验极差。
实现 Markdown↔ HTML 互转,支持导出 PDF,用于用户请求的文档格式转换。
立即学习“前端免费学习笔记(深入)”;
- ✅ 正确做法:在移动断点内,给
li加position: relative,子<ul></ul>默认display: none,再用 JavaScript 切换show类控制显隐 - ❌ 仅靠 CSS 媒体查询隐藏子菜单:未解决触摸设备无 hover 状态的问题,悬停残留逻辑仍会干扰点击
- ⚠️ 注意:iOS Safari 对
:hover支持不稳定,首次点击会触发一次 hover,第二次才真正点击,建议小屏一律弃用:hover控制二级菜单
真正难的不是写出能展开的二级菜单,而是让它的 DOM 结构经得起屏幕阅读器读取、SEO 抓取、移动端点击、键盘 Tab 导航 —— 每一层 <ul></ul> 是否有明确的 role="menu" 和 aria-haspopup,往往比动画效果更重要。


















