长按触发系统菜单与 :active 无关,:active 仅响应瞬时点击,而系统菜单由 touchstart 后约 350ms 长按触发;禁用菜单需同时设置 -webkit-touch-callout: none 和 user-select: none,且需配合 role="button" 和 tabindex="0" 保证 :active 生效。

长按触发系统菜单和 :active 无关
:active 伪类只响应“按下→释放”这个瞬时交互,它不处理长按。系统默认菜单(如“复制”“搜索”“翻译”)是浏览器/OS 层的原生行为,由 touchstart 后持续超过约 350ms 触发,和 CSS 的 :active 完全不同机制。你看到菜单弹出,不是 :active 生效了,而是系统接管了这次长按操作。
真正触发菜单的是 user-select 和 touch-callout
移动端长按菜单是否出现,取决于两个关键 CSS 属性是否被禁用:
-
-webkit-touch-callout: none:iOS Safari 专属,控制是否显示那个带“复制”“分享”的气泡菜单 -
user-select: none(及-webkit-user-select: none):阻止文本选中,间接抑制部分机型的长按菜单(尤其 Android Chrome)
只写 div:active { background: red; } 对禁用菜单毫无作用。必须显式加这两条,且需作用在目标元素或其父容器上。
为什么加了 ontouchstart="" 还弹菜单?
给元素加 ontouchstart="" 只是激活 :active 的渲染时机,它不会阻止系统级长按行为。常见误区是以为“监听了触摸就等于接管了所有触摸逻辑”——其实不是。即使你绑了 touchstart 和 touchend,只要没调用 event.preventDefault(),长按仍会穿透到系统层。
更稳妥的做法是:
- 在目标元素上同时设置
-webkit-touch-callout: none和user-select: none - 如果还需拦截长按逻辑(比如实现自定义长按菜单),在
touchstart中记时间戳,在touchend里判断间隔,超过阈值再preventDefault() - 避免对
body或全局设这些属性,容易误伤可选中文本区域
移动端 :active 和长按菜单是两套并行系统
很多人把“点了没反馈”和“长按弹菜单”混为一谈,其实它们走的是完全不同的路径::active 是样式引擎在毫秒级内切换状态;长按菜单是事件系统在几百毫秒后发起的原生 UI 调用。修复前者靠语义化标签 + touch-action + 激活策略;修复后者必须靠 user-select 和 -webkit-touch-callout 这类防御性 CSS。
最容易被忽略的是:同一元素上,user-select: none 必须和 :active 规则共存,否则禁用了菜单,但按下反馈可能因缺少交互语义而失效——尤其是 iOS 上,div 不加 role="button" tabindex="0",就算写了 :active 也大概率不渲染。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











