navigator.vibrate() 是移动端触控振动唯一标准API,但iOS基本不支持,Android需在用户手势事件中同步调用且参数严格受限,必须配合视觉反馈作为保底。

移动端网页按钮的触控振动反馈,navigator.vibrate() 是唯一标准途径,但它在 iOS 上基本不可用,Android 也只在特定条件下生效——别把它当“开关”,得当“条件触发的系统请求”来处理。
必须在用户手势事件中同步调用 vibrate()
这是失效率最高的原因。哪怕代码完全正确,只要不是直接写在 click、touchend 或 pointerdown 的事件处理器里,就大概率静默失败。
- ✅ 正确:
button.addEventListener('pointerdown', () => navigator.vibrate(150))——pointerdown比click更早触发,兼容触摸和鼠标,且不会因页面跳转或防抖逻辑中断 - ❌ 错误:在
fetch().then()、setTimeout、DOMContentLoaded或 React 的useEffect里调用 —— 浏览器直接忽略,不报错也不震 - ⚠️ 注意:Chrome 96+ 要求页面处于前台活跃状态;切到后台再切回来,首次震动可能需重新点一次按钮才能恢复权限
iOS Safari 实际上不支持震动
不是“兼容性差”,是 Apple 根本没实现。即使你看到 navigator.vibrate 是函数,它在 iOS 上也始终返回 false 或静默失败。所谓“iOS 16.4+ 支持”,仅指极少数场景下可能震一次 ≤15ms 的脉冲,且需同时满足:HTTPS + 用户已开启「辅助功能 → 触感反馈」+ 页面此前已有合法手势触发过震动。
- 别传
[200, 100, 200]或200给 iOS —— 它不会震,也不会警告 - 别 fallback 到播放震动音效 —— 手机外放“嗡”声既失真,又可能在静音模式下突然出声,干扰用户
- 真实可行的降级:统一用
scale(0.98)+background-color瞬变 +box-shadow收缩,配合transition: all 0.1s ease
参数格式与平台差异必须硬编码区分
navigator.vibrate() 对输入极其敏感,类型、长度、数值范围稍有偏差就会被不同系统静默丢弃。
立即学习“前端免费学习笔记(深入)”;
- ✅ 安全参数:单数字
100~200(Android 稳定,iOS 可能忽略但不报错);数组如[150, 50, 150](仅 Android 有效,iOS 忽略) - ❌ 危险参数:
"150"(字符串)、[100, 200, 300](奇数长度)、[0, 100](部分 Android 截断为[100]或丢弃) - ⚠️ 总时长限制:Android 通常截断 >5000ms 的请求;小米 MIUI 强制 ≤1000ms;iOS 硬性 ≤500ms,实测 ≥16ms 就常被系统截断
别让震动成为关键反馈路径
震动永远只是增强项。用户可能开了「减少动态效果」、用了屏蔽振动的国产浏览器(如华为 EMUI 内置浏览器)、正在后台标签页、甚至设备根本没马达——这些都会让 vibrate() 归零。
真正要保底的,是在每次震动调用后立刻执行视觉反馈:比如给按钮加 class="is-shaking",用 CSS @keyframes shake 配合 translateX() 实现非对称抖动,并在 animationend 后移除 class。这样无论震动是否生效,用户都能感知操作已被响应。



















