@media (hover: none) and (pointer: coarse)是最可靠判断典型触控交互状态的方式,它通过排除悬停能力并确认粗粒度指针,精准覆盖手指操作场景,而单独使用二者均会因混合设备或误报导致误判。

@media (hover: none) and (pointer: coarse) 是目前最可靠的方式,它不依赖设备型号或 UA 字符串,而是基于浏览器报告的输入能力组合判断“当前是否处于典型触控交互状态”。单独用 hover: none 或 pointer: coarse 都会误判。
为什么不能只用 hover: none
这个条件只表示“设备不具备悬停能力”,但不等于“正在用手指操作”:
– Windows 触控笔记本(如 Surface)接了鼠标时仍匹配 hover: hover,哪怕你正用手指点屏幕
– 某些 Android 浏览器(如旧版 Samsung Internet)错误报告 hover: hover,导致漏掉真实触控场景
– iOS 13.4+ 和 iPadOS 默认报告 hover: hover,即使没连外设——这是规范要求,不是 bug
为什么不能只用 pointer: coarse
这个值表示“当前活跃指针是粗粒度”,但它会被非触控设备触发:
– 桌面触控屏(Surface 合盖模式)可能同时满足 pointer: coarse 和 hover: hover
– 游戏手柄、遥控器、甚至某些绘图板也归类为 coarse
– 它不区分“当前是否只能靠触摸”,只是说“有至少一个粗粒度输入源”
必须组合使用 (hover: none) and (pointer: coarse)
这个组合才能逼近真实触控场景:
– hover: none 排除所有具备悬停能力的设备(比如带鼠标的二合一)
– pointer: coarse 确认当前主指针是手指级精度
– Safari、Chrome、Firefox 全部支持,且行为一致
– 适合用于:默认显示 .tooltip、展开一级导航菜单、设置 min-height: 44px 点击区
示例写法:
@media (hover: none) and (pointer: coarse) {
.nav-item > .submenu { display: block; }
.btn { padding: 12px 20px; }
}
动态切换输入方式时,CSS 媒体查询不够用
媒体查询在页面加载时求值,不会自动响应用户中途插拔鼠标或切换指针类型。真正难处理的是混合设备——比如 iPad 用户开会时临时接上蓝牙鼠标,又切回手指操作。这时候:
– 用 window.matchMedia('(hover: none)') 监听变化比轮询高效
– 在首次 pointerdown 且 event.pointerType === 'touch' 时,可 JS 注入 touch-mode class
– 不要监听 touchstart,iOS 已限制其触发时机,且桌面模拟器也会误报
– ontouchstart in window 更不可靠,Chrome DevTools 模拟器和部分 Linux 桌面浏览器都返回 true,但物理上根本不支持触摸


















