@media (hover: hover) 是唯一能准确判断设备是否支持稳定悬停能力的 CSS 媒体特性,它依据实际输入方式而非 userAgent 或 ontouchstart 等不可靠 JS 检测,且具备动态响应能力,但需配合 pointer: fine 使用并注意旧内核兼容性。

@media (hover: hover) 是唯一能反映设备是否具备悬停能力的 CSS 媒体特性,不是判断“是不是手机”,而是判断“当前输入方式能否稳定维持悬停状态”。
为什么不能用 ontouchstart 或 userAgent 检测
这些 JS 方式只说明浏览器“注册了触控事件”或“字符串里有 Mobile”,和真实输入能力无关:
• 'ontouchstart' in window 在 Chrome 桌面版、Edge 开发者工具模拟器里也返回 true;
• navigator.userAgent.includes('Mobile') 会把 iPad 横屏、折叠屏展开态、甚至某些 Linux 笔记本都错判为“移动端”;
• 它们无法响应外接鼠标后的动态切换(比如 iPad 插上妙控板,悬停能力立刻生效)。
@media (hover: hover) 的实际行为边界
这个查询在 Safari 15.4+、Chrome 82+、Firefox 68+ 中可靠支持,但旧版微信 X5 内核、UC、QQ 浏览器会直接忽略整块规则——所以它只能用于渐进增强,不能作为核心交互开关:
• @media (hover: hover) 匹配时,才启用 :hover 样式、过渡动画、延迟展开菜单;
• @media (hover: none) 匹配时,应禁用依赖持续悬停的交互(如下拉菜单自动展开、tooltip 浮层);
• 不要把 :hover 样式写在媒体查询外面,否则 iOS Safari 点击后会短暂触发一次再卡住;
• 组合 (pointer: fine) 更稳妥:@media (hover: hover) and (pointer: fine) 能排除 Surface Pro 触控模式、带触控笔但无鼠标场景。
容易被忽略的动态响应问题
CSS 媒体特性是实时更新的,不是页面加载时快照:
• iPad 连上蓝牙鼠标后,@media (hover: hover) 会立即生效,:hover 样式随之启用;
• 你的 CSS 必须能承受这种切换:比如不要用 display: none + :hover 控制菜单显隐,而要用 opacity + visibility 配合 transition;
• JS 中可用 window.matchMedia("(hover: hover)").matches 获取当前状态,并监听 change 事件做轻量同步;
• 若需兼容 X5 内核等老环境,降级方案得靠 JS 主动加 is-touching 类,而非依赖媒体查询。
立即学习“前端免费学习笔记(深入)”;


















