触屏设备无法用 :hover 显隐子菜单,因其 hover 仅短暂触发且不支持链式传递;应使用 @media (hover: none), (pointer: coarse) 识别触屏,并结合 :focus-within 与 data-open 控制显隐,同时确保视觉连续性与语义结构。

触屏设备为什么不能用 :hover 显隐子菜单
因为 :hover 在 iOS Safari、Android Chrome 等主流触屏浏览器中,只在「模拟悬停」的极短窗口内触发(比如点击后短暂高亮),且不支持链式悬停传递。一旦手指抬起,:hover 状态立即丢失,二级菜单根本来不及展开——这不是 bug,是规范行为。
用 @media (hover: none) 或 @media (pointer: coarse) 识别触屏
别再用 @media (max-width: 768px) 判断是否为移动端:折叠屏横屏时宽度超 1000px 却无 hover;小屏 Windows 笔记本 1366×768 却支持精细指针。真正可靠的依据是设备能力:
-
@media (hover: none):明确表示该设备不支持 hover(几乎所有纯触屏设备) -
@media (pointer: coarse):表示主要输入方式为触摸(粗粒度指针),比hover: none更早生效(如部分带触控笔的二合一设备) - 两者建议同时写:
@media (hover: none), (pointer: coarse)
触屏下必须用 :focus-within + data-open 控制显隐
仅靠 :focus-within 不够稳定(键盘用户可用,但触屏首次点击无法自动 focus),所以得配合 JS 切换 data-open="true" 属性,再用 CSS 响应它:
- HTML 中每个可展开项要加
class="has-submenu",子菜单是其直接子元素:<ul class="submenu"></ul> - CSS 规则必须成对出现:
.has-submenu:focus-within > .submenu和.has-submenu[data-open="true"] > .submenu - 禁用所有
:hover > .submenu规则在触屏媒体查询内,避免干扰 - 子菜单自身必须设
position: absolute,且一级用top: 100%,二级起用left: 100%,不能统一写top: 0; left: 0
视觉连续性问题:鼠标/手指移向子菜单时闪退
这是最常被忽略的实操坑——不是代码写错,而是父容器没“兜住”子菜单区域。触屏虽无 hover 移动路径,但焦点切换或 JS 激活后,若父子菜单之间有间隙,:focus-within 会因 DOM 聚焦中断而失效:
- 给
.has-submenu加padding-bottom: 4px或margin-bottom: -4px,让子菜单顶部紧贴父项底部 - 避免用
transform: translateY(100%)替代top: 100%,否则:focus-within的触发边界可能错位 - 子菜单的
opacity和visibility必须配合过渡,禁用display: none—— 否则屏幕阅读器跳过整个结构
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











