同源 iframe 高度自适应需在 onload 后用 scrollHeight 获取真实内容高度并设 style.height,跨域则必须通过 postMessage 双向通信且校验 origin;height: 100% 无效,CSS 重置和 origin 校验是关键前提。

同源 iframe 用 load + scrollHeight 最简可行
只要 iframe 的 src 和父页协议、域名、端口完全一致,就能直接读取子页 DOM。关键不是“设 height=100%”,而是等加载完成再取真实内容高度。
常见错误是:在 iframe 标签写完就立刻读 contentDocument.body.scrollHeight,此时 DOM 还没渲染,返回 0 或极小值;或者没重置子页 body 默认 margin,导致高度多出 8px。
-
iframe.onload触发后,加一层setTimeout(() => { ... }, 0)更稳妥——让浏览器完成重排后再读高 - 取高优先用
document.documentElement.scrollHeight, fallback 到body.scrollHeight,避免 IE 兼容问题 - 子页必须声明
body { margin: 0; padding: 0; },否则高度不准 - 父页设置
ifr.style.height = Math.max(height, 300) + 'px',防空内容塌陷
跨域 iframe 必须靠 postMessage 双向通信
跨域时 contentDocument 被浏览器拦截,scrollHeight 读不到,load 事件也拿不到尺寸。唯一合规路径是子页主动上报——这不是“可选优化”,是强制前提。
容易踩的坑:父页不校验 event.origin 就直接执行 ifr.style.height,会埋 XSS 风险;子页在 DOM 尚未 ready 时就发消息,父页收到 0 高度。
立即学习“前端免费学习笔记(深入)”;
- 子页在
window.addEventListener('load', () => { ... })里计算document.body.scrollHeight,再window.parent.postMessage({ type: 'resize', height }, '*') - 父页监听
window.addEventListener('message', e => { if (e.source !== ifr.contentWindow || e.origin !== 'https://trusted.com') return; ... }) - 子页若用 Vue/React,需确保在
mounted或useEffect后再发消息,避开 SSR 渲染阶段
height: 100% 在 iframe 上根本不起作用
写 <iframe height="100%"> 或 CSS 设 height: 100%,99% 场景下都无效——因为百分比高度依赖父容器有明确 height 值,而 html、body 默认是 auto。
有人试过给父容器加 display: flex 或 grid,但若没显式设 height: 100vh 或固定像素高,iframe 依然塌缩成几像素。这不是 bug,是 CSS 规范行为。
- 要满屏显示,必须逐级设
html, body, .wrap, iframe { height: 100%; margin: 0; padding: 0; } - 移动端 Safari 有 viewport 动态变化问题,建议用
height: 100vh替代100%,并监听resize事件重新计算 -
sandbox属性若含"allow-scripts"才能运行子页的postMessage逻辑,漏配会导致静默失败
动态内容更新后高度不刷新?得监听 resize 或手动触发
子页内容由 JS 异步加载(比如搜索结果、分页列表),首次 load 完后高度就固定了,后续 DOM 变化不会自动同步。这不是父页代码写错了,是机制限制。
同源场景下可以监听子页 window 的 resize 事件(需子页主动 dispatchEvent(new Event('resize')));跨域只能靠子页再次 postMessage 新高度。
- 子页每次内容重绘后(如
innerHTML替换、Vuev-if切换),都要重新计算并发送postMessage - 避免高频触发:用
throttle包裹高度计算逻辑,间隔至少 100ms - 父页收到重复高度值时可跳过 DOM 更新,减少 layout thrashing
scrollHeight 失准,后者让跨域方案形同虚设。这两处不处理,其他逻辑再完整也没用。



















