最省事方式是直接嵌入成熟在线编辑器(如RunJS、CodePen),但需注意其嵌入策略变化与CSP白名单配置;自研方案必须用sandbox+srcdoc隔离,禁用allow-same-origin并HTML编码输入以防XSS。

用 iframe 嵌入现成的在线编辑器最省事
直接嵌入成熟服务(如 JSFiddle、CodePen、Editor.md、RunJS)是最快落地的方式,不用自己搭后端或处理沙箱安全。但要注意它们的嵌入策略在变:CodePen 的 pen 支持 height 和 theme-id 参数,但默认禁止跨域 postMessage 通信;JSFiddle 的 fiddle 嵌入需开启 “Allow embedding” 设置,否则 iframe 会显示空白。
实操建议:
- 优先选
https://runjs.dev/embed/xxx—— 它专为嵌入设计,支持height、autoResize、showConsole等参数,且默认允许postMessage - 避免用
https://jsfiddle.net/.../embedded/老链接,新版已重定向到/embed/,且必须带?tabs=js,html,css,result才能显示完整窗口 - 若页面启用了
Content-Security-Policy,需确保frame-src或child-src白名单包含目标域名,否则 iframe 会被拦截并静默失败
自己实现 HTML 运行框要防执行污染
用 iframe sandbox + srcdoc 是唯一安全的纯前端方案。不能用 eval()、new Function() 或 document.write() 直接执行用户输入——这些会绕过同源策略,污染当前页面作用域,甚至触发 XSS。
关键点:
立即学习“前端免费学习笔记(深入)”;
-
iframe必须带sandbox="allow-scripts",且**不能加allow-same-origin**,否则srcdoc内脚本可读取父页面 DOM -
srcdoc的内容必须 HTML-encode 用户输入的<、>、"、&,否则闭合标签会导致注入(比如用户输</iframe><script>alert(1)</script>) - 运行按钮点击后,用
iframe.contentDocument.write(htmlStr)写入,再调用iframe.contentDocument.close()触发渲染 —— 不要用innerHTML替代,它不触发 script 执行
iframe srcdoc 在 Safari 和旧版 Edge 中有兼容性坑
srcdoc 属性在 Safari 9+、Edge 14+、Chrome 20+ 支持良好,但 Safari 15.4 之前对 srcdoc 中的 <script type="module"> 不支持动态 import;Edge 18 及更早版本会忽略 srcdoc 并 fallback 到空 src,导致白屏。
应对方式:
- 检测
"srcdoc" in document.createElement("iframe"),不支持时降级为预设 demo 页面(如about:blank?demo)或提示“请换浏览器” - 避免在
srcdoc中使用import.meta.url或顶层await,Safari 对模块上下文初始化仍不稳定 - 如果必须支持 IE,只能用
data:text/html,URL 方案,但 IE11 不支持 data URL 中的 script 执行,需额外注入 base64 编码的 JS 字符串并eval—— 这种方案已不推荐
想让运行结果和父页面样式隔离?别只靠 iframe
iframe 确实天然隔离样式和脚本,但用户写的 CSS 可能用 body { margin: 0 } 或 * { box-sizing: border-box } 影响内部布局,而你无法控制其 reset 效果。更麻烦的是:现代框架(如 React/Vue)组件内联样式或 CSS-in-JS 生成的类名,可能被父页面全局 CSS 意外覆盖。
稳妥做法:
- 在
srcdoc的<head>中插入一个最小 reset:<style>*{margin:0;padding:0;box-sizing:border-box}</style> - 运行前把用户 HTML 包进一层
<div id="sandbox-root">...</div>,并在<head>加<style>#sandbox-root{isolation:isolate}</style>,防止 mix-blend-mode 或 filter 泄露 - 如果用户代码含
<link rel="stylesheet">,注意 CORS 限制 —— 外链 CSS 无法加载时,iframe不报错,只会静默忽略,建议预检fetch(url).then(r => r.ok)后再写入
真正难的不是让代码跑起来,而是让用户写的任意 HTML/CSS/JS 不破坏你的页面、不逃逸沙箱、不在 Safari 里突然失灵 —— 这些边界情况,往往只在用户真实输入后才暴露。



















