iframe 的 sandbox 属性会静默拦截 tel:、sms:、intent: 等非 http 协议跳转,且无对应标准 token(如 allow-tel)可放行;需由父页面通过 postmessage 接收请求并执行顶层跳转,同时注意 ios safari 手势触发限制及各平台兼容性问题。

iframe sandbox 会直接拦截 tel:、sms:、intent: 等协议跳转
加了 sandbox 属性(哪怕空值)后,所有协议跳转行为都会被静默拦截——tel:+8613800138000、sms:10086?body=help、intent://... 全部失效,点击无反应,控制台不报错,Network 面板也看不到请求发出。这不是 JS 执行问题,是浏览器在解析 URL 阶段就丢弃了这些 scheme。
sandbox="allow-top-navigation" 也不能放行 tel/sms 协议
allow-top-navigation 只解禁 window.top.location.href = "https://..." 这类 HTTP(S) 跳转,对非 HTTP 协议完全无效。即使你写了 sandbox="allow-scripts allow-top-navigation",@#@#@#@#@#@#@#@#@#@0 依然点不动。
- 浏览器明确将
tel:、sms:、geo:、market:等视为“导航能力之外”的独立能力,不在任何现有 sandbox token 的覆盖范围内 -
allow-popups对这些协议也无效——它只管window.open()和target="_blank"的新窗口行为 - 目前没有标准 sandbox token 能授权 tel/sms 调用;Chrome、Firefox、Safari 均未实现类似
allow-tel的扩展 token
想让内嵌页面调起外部 App,必须绕过 sandbox 限制
如果业务确实需要拨号或发短信(比如客服卡片),唯一可行路径是:由父页面托管跳转逻辑,iframe 仅通过 postMessage 触发。
- iframe 内禁止写
<a href="tel:..."></a>,改用window.parent.postMessage({ action: "call", number: "138..." }, "*") - 父页监听时必须校验
event.origin,不能只靠sandbox="allow-scripts"就信任消息来源 - 父页收到后执行
window.location.href = "tel:138..."—— 这个跳转发生在顶层上下文,不受 iframe sandbox 约束 - 注意:iOS Safari 对
tel:跳转有额外限制(需用户真实点击触发),异步 postMessage 后立刻跳转可能被拦截,建议加一次用户手势确认(如弹出确认按钮)
容易被忽略的兼容性细节
即使父页主动跳转,也要注意不同平台的实际表现:
- Android Chrome 支持
tel:、sms:、intent:,但部分定制 ROM 会屏蔽intent: - iOS Safari 仅支持
tel:和sms:,且要求链接在用户点击事件中直接触发,不能延迟或封装在 Promise 里 -
market://(安卓应用市场)和itms-apps://(iOS App Store)在 sandbox 外调用也常因系统策略失败,应降级为网页版下载页 - 微信内置浏览器、QQ 浏览器等 WebView 会进一步拦截这些协议,需提前 UA 检测并 fallback 到二维码或客服电话展示
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











