空sandbox属性会导致iframe白屏且JS完全不执行,因浏览器跳过HTML解析并静默拦截所有主动行为;必须显式声明如allow-scripts等白名单token才能逐项放行,且需配合Blob URL、postMessage和Shadow DOM等实现完整隔离。

iframe sandbox 属性必须带明确 token,空值会导致白屏
只写 sandbox 或 sandbox="" 不是“开启隔离”,而是让 iframe 连 HTML 解析都跳过——Network 面板会显示 net::ERR_BLOCKED_BY_RESPONSE,页面彻底空白。这不是 bug,是浏览器底层拦截策略:没声明任何权限,就拒绝加载响应体。
真正起效的是显式白名单,比如:sandbox="allow-scripts allow-forms"。每个 token 之间用空格分隔,不能加逗号,也不能省略引号。
-
allow-scripts:必须加,否则 JS 不执行(包括图表库、Vue 实例初始化) -
allow-forms:仅当沙箱内有<form>且需提交时才加;提交目标受 CORS 控制,不自动获得网络权限 - 别加
allow-same-origin:除非 src 确实与父页同协议+域名+端口;不同源时该 token 被静默忽略,还暴露配置疏漏
Blob URL 是唯一能保证 JS 上下文彻底重置的方案
用 iframe.contentDocument.write() 或 srcdoc 每次重写 HTML,看似清空了 DOM,但旧 JS 执行环境残留——const x = 1 声明过一次,再写一遍就报 Identifier 'x' has already been declared。这不是语法错误,是解析阶段冲突,try/catch 捕获不到。
Blob URL 是浏览器原生支持的“一次一文档”机制:
立即学习“前端免费学习笔记(深入)”;
-
new Blob([htmlString], {type: 'text/html'})创建内容载体 -
URL.createObjectURL(blob)生成唯一blob:协议地址(自动绑定null origin) - 赋值给
iframe.src后,浏览器强制加载新文档,变量、定时器、事件监听器全部清零 - 记得在
iframe.onload中调用URL.revokeObjectURL(url),否则内存泄漏
postMessage 是沙箱内外通信的唯一合法通道
沙箱 iframe 的 window.parent 默认不可访问,localStorage、document.cookie 绑定到临时 null origin,刷新即空——DevTools 的 Application 面板显示可能误导,实际要用 Object.keys(localStorage) 在控制台验证。
所有状态同步必须走 postMessage:
- iframe 内:用
window.parent.postMessage({ type: 'INPUT_CHANGE', value: 'xxx' }, '*')上报变更 - 父页监听:必须校验
event.origin,不能写'*'(生产环境必须限定为具体域名) - 别在 iframe 内尝试读写父页 DOM、调用父页函数,这些行为被 sandbox 强制阻断,无报错、无提示
样式和自定义元素命名必须带业务前缀,否则必然撞车
多团队共用一个页面时,class="btn"、id="modal"、my-button 这类泛化名一定会冲突。HTML 没有原生命名空间,靠约定兜底成本最低。
- 自定义元素名必须含破折号:
shop-button✅,mybutton❌(注册直接抛DOMException) - class 名用 BEM 规范:
shop-button__icon,不用shop-button-icon(易与其它连字符命名混淆) -
data-*属性必须带业务上下文:data-shop-id="123",不是data-id="123"(三个月后没人知道这是商品 ID 还是用户 ID) - Shadow DOM 是唯一真隔离方案:必须在
constructor()中调用this.attachShadow({ mode: 'open' }),延迟到connectedCallback就晚了
复杂点在于:沙箱不是开个 iframe 就完事,它是一组约束的组合——Blob URL 解决 JS 上下文复用,sandbox token 控制能力边界,postMessage 定义通信契约,BEM + Shadow DOM 切断样式污染。漏掉任意一环,联合调试时就会出现“明明我改了,别人那边却没变”或“我的按钮样式把别人的弹窗盖住了”这类问题。



















