纯CSS多级菜单在手机上点一下跳转而非展开,因触屏设备将首次点击视为模拟hover、第二次才触发链接;需用@media (hover: none), (pointer: coarse)禁用:hover规则,改用data-open+JS控制,并确保每级li设position:relative及has-submenu类。

为什么纯 CSS 多级菜单在手机上点一下就跳转,而不是展开?
因为 iOS 和 Android 浏览器把第一次点击解释为“模拟 hover”,第二次才触发链接——这不是 bug,是规范行为。CSS 没有 :click 伪类,:hover 在触屏设备上天然不可持续。
- 别试图用
@media (max-width: 768px)强行保留:hover,这会让菜单在折叠屏(如 Galaxy Z Fold 横屏)上失效,而在小屏 Windows 笔记本上又误启用 - 正确做法是用
@media (hover: none), (pointer: coarse)主动禁用所有:hover > .submenu规则 - 移动端必须降级为点击展开,且得靠
data-open="true"+ 简单 JS 控制,CSS 只管显隐样式 - 键盘用户依赖
:focus-within,所以每一级<li class="has-submenu">都要同时写.has-submenu:hover > .submenu和.has-submenu:focus-within > .submenu
鼠标一移向子菜单就闪退,怎么修?
根本不是动画慢,而是父 <li> 和子 <ul class="submenu"> 之间存在视觉间隙,导致 :hover 状态瞬间中断。
- 给父
<li>加padding-bottom: 2px或margin-bottom: -1px,物理覆盖那条缝隙 -
.submenu必须设position: absolute; top: 100%; left: 0;,不能用transform: translateY(100%)—— 它不参与布局计算,填不了缝 - 父
<li>必须显式设position: relative,否则子菜单会相对视口定位,飞出导航栏 - 外层
<nav>或<header>别设overflow: hidden,否则子菜单被裁切,看起来像“消失”
三级菜单错位、叠在左边或顶部,怎么调?
错位通常是因为定位上下文丢失或 left/top 值没分层处理。所有子菜单用同一套 top: 100%; left: 0; 是最大误区。
- 一级
.submenu:保持top: 100%; left: 0; - 二级及以上:统一加
.has-submenu:hover .submenu, .has-submenu[data-open="true"] .submenu { left: 100%; top: -1px; }——top: -1px是为了对齐上一级项的边框,避免新缝隙 - 每一级
<li class="has-submenu">都要设position: relative,否则二级菜单找不到定位基准 -
z-index只需在外层<nav>设一个基础值(如z-index: 100),子菜单靠层叠上下文自然堆叠,别每级都设不同值
移动端用 display: none 还是 visibility: hidden?
必须用 display: none 初始隐藏,但切换时不能只靠它做过渡——因为 display 不支持 CSS 动画。
立即学习“前端免费学习笔记(深入)”;
- 正确组合:
.submenu { display: none; opacity: 0; visibility: hidden; transition: opacity 0.2s; } - 触发时:
.has-submenu[data-open="true"] .submenu { display: block; opacity: 1; visibility: visible; } - 禁用
pointer-events: none直接控制显隐——它会让屏幕阅读器跳过整个子菜单结构 - 别在 HTML 中用 JS 动态插入子菜单,
<ul class="submenu">必须是父<li>的直接子元素,否则 CSS 选择器.has-submenu:hover > .submenu失效
<li> 都得带 class="has-submenu" 并设 position: relative,漏掉任意一级,定位就全乱。还有就是 @media (hover: none) 下,所有 :hover 规则必须成对删减,不能只删一半。


















