纯CSS的:hover在触屏设备上不可靠,是因W3C规范允许浏览器弱化或忽略:hover;iOS/Android仅首次触摸短暂模拟hover(约300ms延迟),第二次才触发click,导致菜单闪退或无法展开。

为什么纯CSS的:hover在触屏设备上根本不可靠
这不是你代码写错了,是浏览器规范行为:iOS Safari 和安卓 WebView 压根不支持持续 :hover 状态。第一次点击被当作模拟 hover(延迟约 300ms,且仅首次),第二次才触发 click——导致菜单点一下就收、点两下才跳转,或干脆不展开。
用 @media (max-width: 768px) 切换交互逻辑更危险:Galaxy Z Fold 横屏宽度超 1000px 却无 hover;1366×768 笔记本却完全支持精细指针。尺寸 ≠ 交互能力。
-
@media (hover: hover) and (pointer: fine)下启用:hover显隐 -
@media (hover: none), (pointer: coarse)下彻底禁用所有:hover规则 - 所有
:hover必须成对出现:.has-submenu:hover > .submenu和.has-submenu:focus-within > .submenu
如何让键盘用户和屏幕阅读器也能操作多级菜单
WCAG 2.1 AA 合规要求 :focus-within,但只加在第一级远远不够——二级菜单项若无法获得焦点,Tab 键一按就跳过整个子结构。
- 每级可展开项(如
)必须加tabindex="0" - 子菜单(
)必须是其**直接子元素**,否则:focus-within不触发 - 禁用
display: none:它会让屏幕阅读器跳过整个子菜单 DOM 结构 - 初始状态应为:
.submenu { visibility: hidden; opacity: 0; pointer-events: none; }
移动端点击展开必须用 data-open,别碰 display: none
JS 只负责切换属性,CSS 控制显隐与过渡——这是解耦的关键。用 display: none 切换,动画失效、无障碍断链、状态难追踪。
- JS 只做一件事:
el.dataset.open = el.dataset.open === "true" ? "false" : "true" - CSS 控制效果:
[data-open="true"] .submenu { visibility: visible; opacity: 1; pointer-events: all; } - 绝对禁止在媒体查询里写
.submenu { display: block !important; }——它会覆盖data-open,导致无法收起 - 监听
click而非touchstart:iOS Safari 对click的兼容性更稳
定位错乱、菜单飞走、闪退的三个硬性修复点
90% 的“菜单消失”“飘到左上角”“鼠标一移就关”,都源于定位上下文和隐藏方式错误,跟动画参数无关。
- 每级
都必须显式设position: relative——不是只加一级 - 子菜单用
left: 100%(而非top: 0; left: 0)向右展开,避免二级菜单重叠或飞出视口 - 鼠标移入途中闪退?不是 bug,是视觉连续性没做:用
transform: translateY(100%)替代top: 100%,配合transition更稳 - 别依赖
float: left布局一级导航——z-index 会失效;改用display: flex并确保父容器有position: relative
关键不在“怎么写更多 CSS”,而在守住这四条线:交互能力判断、定位上下文、显隐控制方式、焦点可访问路径。漏掉任何一条,菜单就在真实设备上半瘫痪。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











