<p>iframe sandbox 属性不加值等于直接拒止响应体,Shadow DOM 是唯一原生隔离机制,HTML 模板需统一托管与校验,class/id/data-* 必须绑定组件上下文。</p>

iframe sandbox 属性不加值等于直接拒止,不是隔离
只写 sandbox 或 sandbox="" 不是“启用沙箱”,而是告诉浏览器:拒绝解析整个响应体。Network 面板会显示 net::ERR_BLOCKED_BY_RESPONSE,iframe 空白、无 HTML 解析、控制台静默——这不是 bug,是规范行为。
真正起效的必须是带明确权限 token 的字符串,例如 sandbox="allow-scripts"。每个 token 是白名单项,不列就不给,写了才开:
-
sandbox="allow-scripts":仅解禁外链脚本加载与执行,但内联事件(onclick、onload)、javascript:void(0)、document.write()仍被禁止 -
sandbox="allow-scripts allow-same-origin":仅当src确实与父页同源(协议+域名+端口全等)时才生效;不同源时该 token 被浏览器静默忽略 -
sandbox="allow-scripts allow-popups allow-forms":适用于嵌入用户填写的问卷,表单提交需走 CORS,不碰allow-same-origin - 绝对不要写
sandbox="allow-scripts allow-same-origin allow-popups allow-forms allow-top-navigation"——这和没加sandbox几乎一样危险
Shadow DOM 是唯一能强制样式与 JS 隔离的原生机制
用 scoped 属性或 BEM 命名不是沙箱,只是约定。Chrome 120+、Firefox 115+ 已移除 scoped 支持,BEM 无法阻止 JS 查询到全局节点。
必须显式调用 attachShadow({ mode: 'open' }) 创建 shadow root,否则所有“封装”都是假象:
立即学习“前端免费学习笔记(深入)”;
- 直接在宿主元素上写
<style scoped></style>→ 浏览器忽略,样式照常泄漏 - 用
innerHTML = '<style>...</style>'赋值到 shadowRoot →<style>被当作文本节点,不进入 CSSOM - 忘记设置
:host { font-family: inherit; color: inherit; }→ 文字断层,组件视觉割裂 - 异步加载插件 HTML/CSS/JS 时,必须全部注入 shadowRoot,不能漏到主文档;
<script>需显式设type="module"再 append,否则逃逸执行环境
HTML 模板质量同步必须靠 pnpm Workspace + shared package + lint 联动
复制粘贴模板、手动发布 npm 包、Git 子模块,都会导致多组织间 HTML 渲染结果和可访问性不一致。根本解法是统一托管 + 统一校验:
- 把所有公共 HTML 模板(
header.html、card-template.html)放进packages/shared-templates目录 - 各业务仓库通过
"shared-templates": "file:../shared-templates"引用,避免本地覆盖 - 根目录
.htmlvalidate.json统一配置规则:强制img[alt]、禁止内联style、要求lang属性、校验data-命名风格(如"attr-name-style": ["error", "kebab-case"]) - CI 中只跑
pnpm -r --parallel lint:html,失败即阻断合并——别让 “模板没问题” 成为各项目自己的主观判断
class/id/data-* 必须绑定组件上下文,否则命名空间必然冲突
HTML 没有原生模块作用域,所有 class/id 都在全局 flat 命名空间里。class="title" 或 id="modal" 在多组织共存时 100% 冲突。
BEM 是目前最轻量且可落地的解法,但必须严格执行:
- 根元素用唯一 block 名:
class="user-profile",不是class="profile" - 子元素严格双下划线:
class="user-profile__avatar",不写成user-profile-avatar - 状态修饰符用双短横:
class="user-profile--loading",避免is-loading这类无归属的状态名 -
data-属性必须携带业务上下文:data-user-id="123",而非裸名data-id="123";JS 中读取对应el.dataset.userId,前提是命名本身有意义 - 自定义元素名必须含破折号且带统一前缀:
my-button合法,mybutton直接报DOMException;多组织协作建议用orgname-button避免撞车
真实沙箱不是加个属性就完事,它由三重边界构成:iframe 的执行隔离、Shadow DOM 的样式/JS 作用域、shared package 的结构契约。漏掉任何一层,协作规模越大,失真越快。



















