-webkit-touch-callout: none 是 webkit 内核专有属性,仅在 ios safari 及内置 webview 中可禁用长按菜单,但单独使用在 ios 15+ 尤其 16.4+ 常失效,必须配合 -webkit-user-select: none 且作用于目标元素本身;安卓及微信 x5 等需 js 拦截 touchstart 并 preventdefault() 才可靠。

webkit-touch-callout 是什么,它真能禁用长按菜单?
-webkit-touch-callout 是 WebKit 内核(包括 Safari 和所有 iOS WebView)提供的一个非标准 CSS 属性,专门用于控制用户长按可点击元素时是否弹出系统默认菜单(比如“复制”“搜索”“翻译”等)。它只对 <a></a>、<img>、<input> 等原生可交互元素生效,对普通 <div> 或自定义按钮无效——这点常被忽略。
<p>设置为 <code>none 可以隐藏该菜单,但注意:它不阻止长按事件本身,touchstart、touchend 仍会触发;也不影响 contextmenu 事件(桌面端右键),纯移动端行为。
怎么写才真正生效?关键样式和作用范围
必须用 -webkit-user-select: none 配合,否则部分 iOS 版本(尤其是 iOS 15+)下仅设 -webkit-touch-callout: none 可能失效。同时,样式需作用于目标元素本身,不能只写在父容器上。
- 正确写法:
a, button, img { -webkit-touch-callout: none; -webkit-user-select: none; } - 错误写法:
.btn-wrapper { -webkit-touch-callout: none; }—— 父容器设了没用 - 如果用 React/Vue,确保样式未被 scoped 或 CSS-in-JS 覆盖;检查 computed styles 是否真的应用到了目标节点
iOS 16.4+ 的特殊限制:某些场景下它彻底失效
从 iOS 16.4 开始,Apple 对 -webkit-touch-callout: none 做了更严格的限制:当元素具有 href 属性(如 <a href="#"></a>)且内容可被选中或有语义化文本时,系统可能强制恢复菜单,尤其在 VoiceOver 开启时。
- 绕过方式:移除
href,改用role="button"+tabindex="0"+click事件 - 避免用
<a href="javascript:void(0)"></a>—— 这类写法反而更容易触发系统拦截 - 测试真机:模拟器不反映此限制,必须用真实 iPhone/iPad 测试
替代方案:当 CSS 失效时,用 JavaScript 拦截
CSS 不可靠时,可监听 touchstart 并立即 preventDefault(),但要注意副作用:
- 会同时禁用滚动(尤其在
overflow: scroll容器内),需加判断:if (e.target === buttonEl) e.preventDefault() - 不能在
touchend拦截,此时菜单已弹出 - 推荐组合:
buttonEl.addEventListener('touchstart', e => { if (e.target === buttonEl) e.preventDefault(); }, { passive: false });
实际项目里,往往需要 CSS + JS 双保险,尤其面向 iOS 用户较多的 H5 页面。别指望单靠一个属性一劳永逸——WebKit 的行为在小版本间都可能变。











