移动端禁双指缩放需 viewport 四参数全设(width=device-width、initial-scale=1.0、minimum-scale=1.0、maximum-scale=1.0)+ touchstart/gesturestart 双事件拦截(passive: false)+ 按钮级 touch-action: manipulation。

移动端防止用户双指拉伸(即双指缩放),不能只靠一个 user-scalable=no,因为从 iOS 10.3 起,Safari 就主动忽略它——这是 Apple 为保障可访问性做的强制策略。真正有效的做法是 viewport 约束 + 原生手势拦截的组合,缺一不可。
viewport 必须写全这四个参数
仅写 user-scalable=no 已失效,必须同时设定缩放上下限和初始比例:
-
width=device-width:确保视口宽度匹配设备物理宽度 -
initial-scale=1.0:页面加载即按 1:1 渲染,缺失会导致部分安卓 WebView 忽略后续 scale 设置 -
minimum-scale=1.0和maximum-scale=1.0:这才是被所有现代浏览器(包括 iOS Safari)严格遵守的硬性约束
正确写法(必须静态放在 最早位置,JS 动态插入无效):
用 touchstart 拦截双指手势
双指缩放本质是多点触控触发的原生行为,iOS 虽然无视 viewport 的禁用声明,但允许 JS 在 touchstart 阶段拦截:
- 监听
document.documentElement上的touchstart - 判断
event.touches.length > 1,满足则立即event.preventDefault() - 必须传
{ passive: false },否则 Safari / Chrome 会静默丢弃 preventDefault
注意:不要监听 touchmove,太晚;也不要全局禁用所有 touch,否则滚动、点击都会失灵。
补上 gesturestart 防 iOS 系统级缩放
iOS 的双指缩放有一套独立于 touch 的手势事件流,仅拦 touch 不够。必须显式监听并阻止:
document.addEventListener('gesturestart', e => e.preventDefault(), { passive: false })-
gesturechange和gestureend也建议一并监听,增强兼容性 - 这个监听应在 DOM 就绪后执行(如
window.onload或 Vue/React 的挂载钩子中)
按钮等可点击元素加 touch-action: manipulation
针对按钮被双击放大(尤其在表单页),光靠全局设置不够,需细化到元素层:
- 给按钮类选择器加 CSS:
button, .btn { touch-action: manipulation; } - 它让浏览器跳过双击检测逻辑,既消除 300ms 延迟,也阻止该元素上的双击缩放
- 不要写
* { touch-action: manipulation; },否则轮播图、图片放大等正常交互会失效 - 父容器不能设
touch-action: none,否则子元素的 manipulation 会被覆盖











