根据内容调整 iframe 的大小

Posted

技术标签:

【中文标题】根据内容调整 iframe 的大小【英文标题】:Resizing an iframe based on content 【发布时间】:2010-09-14 06:24:43 【问题描述】:

我正在开发一个类似 iGoogle 的应用程序。来自其他应用程序(在其他域上)的内容使用 iframe 显示。

如何调整 iframe 的大小以适应 iframe 内容的高度?

我试图破译谷歌使用的 javascript,但它被混淆了,到目前为止搜索网络没有结果。

更新:请注意,内容是从其他域加载的,因此same-origin policy 适用。

【问题讨论】:

【参考方案1】:

我们遇到了这种类型的问题,但与您的情况略有相反 - 我们将 iframe 内容提供给其他域上的网站,因此 same origin policy 也是一个问题。在谷歌搜索了很多小时后,我们最终找到了一个(有点..)可行的解决方案,您可以根据自己的需要进行调整。

有一种方法可以绕过同源策略,但它需要对 iframed 内容和框架页面进行更改,因此如果您无法在双方都请求更改,则此方法不会很有用对你来说,我害怕。

有一个浏览器怪癖允许我们避开同源策略 - javascript 可以与它​​自己域中的页面通信,也可以与它具有 iframe 的页面通信,但不能与它被加框的页面通信,例如如果你有:

 www.foo.com/home.html, which iframes
 |-> www.bar.net/framed.html, which iframes
     |-> www.foo.com/helper.html

然后home.html 可以与framed.html(iframed)和helper.html(同一个域)通信。

 Communication options for each page:
 +-------------------------+-----------+-------------+-------------+
 |                         | home.html | framed.html | helper.html |
 +-------------------------+-----------+-------------+-------------+
 | www.foo.com/home.html   |    N/A    |     YES     |     YES     |
 | www.bar.net/framed.html |    NO     |     N/A     |     YES     |
 | www.foo.com/helper.html |    YES    |     YES     |     N/A     |
 +-------------------------+-----------+-------------+-------------+

framed.html 可以向helper.html(iframed)发送消息,但不能 home.html(子级无法与父级跨域通信)。

这里的关键是helper.html可以接收来自framed.html的消息,并且还可以与home.html通信

所以本质上,当framed.html 加载时,它会计算出自己的高度,告诉helper.htmlhelper.html 会将消息传递给home.html,然后home.html 可以调整framed.html 所在的 iframe 的大小。

我们发现将消息从framed.html 传递到helper.html 的最简单方法是通过 URL 参数。为此,framed.html 有一个 iframe,其中指定了 src=''。当它的onload 触发时,它会评估自己的高度,并将此时iframe 的src 设置为helper.html?height=N

There's an explanation herefacebook是怎么处理的,可能比我上面的稍微清楚一点!


代码

www.foo.com/home.html 中,需要以下 javascript 代码(可以从任何域上的 .js 文件加载,顺便说一句..):

<script>
  // Resize iframe to full height
  function resizeIframe(height)
  
    // "+60" is a general rule of thumb to allow for differences in
    // IE & and FF height reporting, can be adjusted as required..
    document.getElementById('frame_name_here').height = parseInt(height)+60;
  
</script>
<iframe id='frame_name_here' src='http://www.bar.net/framed.html'></iframe>

www.bar.net/framed.html:

<body onload="iframeResizePipe()">
<iframe id="helpframe" src='' height='0' width='0' frameborder='0'></iframe>

<script type="text/javascript">
  function iframeResizePipe()
  
     // What's the page height?
     var height = document.body.scrollHeight;

     // Going to 'pipe' the data to the parent through the helpframe..
     var pipe = document.getElementById('helpframe');

     // Cachebuster a precaution here to stop browser caching interfering
     pipe.src = 'http://www.foo.com/helper.html?height='+height+'&cacheb='+Math.random();

  
</script>

www.foo.com/helper.html的内容:

<html> 
<!-- 
This page is on the same domain as the parent, so can
communicate with it to order the iframe window resizing
to fit the content 
--> 
  <body onload="parentIframeResize()"> 
    <script> 
      // Tell the parent iframe what height the iframe needs to be
      function parentIframeResize()
      
         var height = getParam('height');
         // This works as our parent's parent is on our domain..
         parent.parent.resizeIframe(height);
      

      // Helper function, parse param from request string
      function getParam( name )
      
        name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
        var regexS = "[\\?&]"+name+"=([^&#]*)";
        var regex = new RegExp( regexS );
        var results = regex.exec( window.location.href );
        if( results == null )
          return "";
        else
          return results[1];
      
    </script> 
  </body> 
</html>

【讨论】:

太棒了,谢谢!我做了一些补充:使用 jQuery 获取 framed.html 中的正文高度(FF 问题,正文不断增长): var height = $(document.body).height();使用 body onload 事件在 home.html 中创建框架,类似于您在 framed.html 中的方法。在 FF 和 Safari 中刷新时不更新框架的地址。 天才!除了 Abdullah 的补充:我没有将 body onload 设置为调用 parentIframeResize(),而是使用 JQuery 来捕获页面加载和任何调整大小的事件:$(document).ready(iframeResizePipe); $(window).resize(iframeResizePipe); 这允许我设置 iframe width="100%" 以及如果窗口宽度更改以使文本换行或其他内容,内部框架将识别出它需要调整大小。 我建议给 iframe id=frame_name_here 一个默认的高度属性,例如 。这意味着当页面加载时,框架内容是可见的。当调整大小发生时,没有“闪烁”。调整大小在页面折叠下方缩小/扩大。如果您知道 iframed 内容的最大高度,则使用该值...这也会带来更好的 noscript 体验。 @Frederico,这种方法仍然有效,但需要修改解决方案才能在最新版本的 FF 和 Chrome 中工作。如果滚动高度大于正在呈现的页面,则滚动高度将不正确地使用 iframe 高度。这会导致 iframe 在每翻一页时潜在地增加 60 像素。所需的解决方法是在带框架的 HTML 中添加一个 ID 元素。获取它的滚动高度而不是文档,它就像一个冠军。 不幸的是,这似乎不再有效。我仔细实现了这一点,但在 Chrome 控制台中收到以下 javascript 错误:Uncaught DOMException: Blocked a frame with origin "example.com" from access a cross-origin frame。【参考方案2】:

如果你不需要处理来自不同域的 iframe 内容,试试这个代码,它会彻底解决问题,而且很简单:

<script language="JavaScript">
<!--
function autoResize(id)
    var newheight;
    var newwidth;

    if(document.getElementById)
        newheight=document.getElementById(id).contentWindow.document .body.scrollHeight;
        newwidth=document.getElementById(id).contentWindow.document .body.scrollWidth;
    

    document.getElementById(id).height= (newheight) + "px";
    document.getElementById(id).width= (newwidth) + "px";

//-->
</script>

<iframe src="usagelogs/default.aspx"   id="iframe1" margin frameborder="0" onLoad="autoResize('iframe1');"></iframe>

【讨论】:

将元素本身传递给函数可能会更优化,以避免您拥有的所有document.getElementById(id)s 并简化代码。 这对我不起作用,因为 contentWindow.document.body.scrollHeight 包含 0 而不是实际高度。 这个解决方案,和我尝试过的所有其他解决方案一样,只有在高度增加时才有效,如果从高页面导航到较短的页面,高度仍然根据第一个的高度设置一。有没有人找到解决这个问题的方法? @Eugenio 和包括我在内的其他所有人,以解决最后一个问题:请参阅***.com/questions/3053072/… 在询问 iframe 内文档的高度之前,您应该将 iframe 对象的高度设置为“自动”。请注意,您应该使用 style.height 而不仅仅是上面答案中的高度 我不明白...您检查是否存在 document.getElementById 然后无论如何都在检查区域之外调用它?【参考方案3】:

https://developer.mozilla.org/en/DOM/window.postMessage

window.postMessage()

window.postMessage 是一种安全启用跨域通信的方法。通常,只有当且仅当执行它们的页面位于具有相同协议(通常都是 http)、端口号(http 的默认值为 80)和主机(模document.domain 被两个页面设置为相同的值)。 window.postMessage 提供了一种受控机制,以在正确使用时安全的方式规避此限制。

总结

window.postMessage,当调用时,会在必须执行的任何挂起脚本完成时在目标窗口调度 MessageEvent(例如,如果从事件处理程序调用 window.postMessage,则剩余的事件处理程序,先前设置的挂起超时, 等等。)。 MessageEvent 具有消息类型,数据属性设置为提供给 window.postMessage 的第一个参数的字符串值,原始属性对应于在时间窗口调用 window.postMessage 的窗口中的主文档的来源。 postMessage 被调用,源属性是调用 window.postMessage 的窗口。 (事件的其他标准属性与它们的期望值一起出现。)

iFrame-Resizer 库使用 postMessage 来保持 iFrame 的大小与其内容一致,并使用 MutationObserver 来检测内容的变化,并且不依赖于 jQuery。

https://github.com/davidjbradshaw/iframe-resizer

jQuery:跨域脚本的优点

http://benalman.com/projects/jquery-postmessage-plugin/

有调整 iframe 窗口大小的演示...

http://benalman.com/code/projects/jquery-postmessage/examples/iframe/

这篇文章展示了如何移除对 jQuery 的依赖... Plus 有很多有用的信息和其他解决方案的链接。

http://www.onlineaspect.com/2010/01/15/backwards-compatible-postmessage/

准系统示例...

http://onlineaspect.com/uploads/postmessage/parent.html

window.postMessage 上的 HTML 5 工作草案

http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages

John Resig 谈跨窗口消息传递

http://ejohn.org/blog/cross-window-messaging/

【讨论】:

postMessage 本身不是跨浏览器的,但 jQuery 插件似乎在必要时可以很好地伪装它。唯一真正的问题是在不支持 postMessage 的情况下添加到 URL 栏中的“垃圾”。 postMessage 似乎是 X-Browser。只有 IE 有 bug 或需要关心的事情: 1. 只能在框架或 iframe 之间进行通信 2. 只能发布字符串。见:caniuse.com/x-doc-messaging 很高兴看到您回答问题,而不是解释有助于解决方案的辅助技术.. periscopedata 正在使用 postMessage,如果它对他们来说足够好,对我们来说就足够了。这是他们的文档:doc.periscopedata.com/docv2/embed-api-options【参考方案4】:

使用jQuery最简单的方法:

$("iframe")
.attr("scrolling": "no", "src":"http://www.someotherlink.com/")
.load(function() 
    $(this).css("height", $(this).contents().height() + "px");
);

【讨论】:

未按要求跨域。【参考方案5】:

最后,我找到了一些其他解决方案,可以使用 window.postMessage(message, targetOrigin); 从 iframe 向父网站发送数据。在这里我解释一下我是怎么做的。

站点 A = http://foo.com 站点 B = http://bar.com

SiteB 正在 siteA 网站内加载

SiteB网站有这行

window.parent.postMessage("Hello From IFrame", "*"); 

window.parent.postMessage("Hello From IFrame", "http://foo.com");

那么siteA有以下代码

// Here "addEventListener" is for standards-compliant web browsers and "attachEvent" is for IE Browsers.
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];


var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";

// Listen to message from child IFrame window
eventer(messageEvent, function (e) 
   alert(e.data);
   // Do whatever you want to do with the data got from IFrame in Parent form.
, false); 

如果你想添加安全连接,你可以在eventer(messageEvent, function (e) )中使用这个if条件

if (e.origin == 'http://iframe.example.com') 
    alert(e.data); 
    // Do whatever you want to do with the data got from IFrame in Parent form.

对于 IE

在 IFrame 内:

 window.parent.postMessage('"key":"value"','*');

外面:

 eventer(messageEvent, function (e) 
   var data = jQuery.parseJSON(e.data);
   doSomething(data.key);
 , false);

【讨论】:

这个解决了我的问题。我不得不说这可能只是因为 iFrame 提供程序使用正确的信息(在我的情况下为帧高度)调度事件。看看它是否适用于任何 iFrame 会很有趣。谢谢@Selvamani【参考方案6】:

http://www.phinesolutions.com/use-jquery-to-adjust-the-iframe-height.html 上的解决方案效果很好(使用 jQuery):

<script type=”text/javascript”>
  $(document).ready(function() 
    var theFrame = $(”#iFrameToAdjust”, parent.document.body);
    theFrame.height($(document.body).height() + 30);
  );
</script>

我不知道你需要在长度上加 30...1 对我有用。

仅供参考:如果您的 iFrame 上已有“高度”属性,则只需添加 style="height: xxx"。这可能不是你想要的。

【讨论】:

正是我所需要的,因为我不做跨域,+1 为有效的 html。 在您点击指向 phinesolutions.com 的链接之前,它现在会显示 NSFW 内容。【参考方案7】:

可能有点晚了,因为所有其他答案都较旧:-) 但是......这是我的解决方案。在实际的 FF、Chrome 和 Safari 5.0 中测试。

css:

iframe border:0; overflow:hidden;

javascript:

$(document).ready(function()
    $("iframe").load( function () 
        var c = (this.contentWindow || this.contentDocument);
        if (c.document) d = c.document;
        var ih = $(d).outerHeight();
        var iw = $(d).outerWidth();
        $(this).css(
            height: ih,
            width: iw
        );
    );
);

希望这对任何人都有帮助。

【讨论】:

@pashute - 你的意思是“跨域”吗? 对不起。意思是:不能跨平台工作...这是一个公共要点:gist.github.com/pashute/c4705ce7f767f50fdf56d0030ecf9192 获取拒绝执行错误。将脚本更改为 type="text/javascript" 没有帮助。也不设置 iframe 的宽度和高度(比如 80%)。【参考方案8】:

此答案仅适用于使用 Bootstrap 的网站。 Bootstrap 的响应式嵌入功能可以完成这项工作。它基于内容的宽度(而不是高度)。

<!-- 16:9 aspect ratio -->
<div class="embed-responsive embed-responsive-16by9">
  <iframe class="embed-responsive-item" src="http://www.youtube.com/embed/WsFWhL4Y84Y"></iframe>
</div>

jsfiddle:http://jsfiddle.net/00qggsjj/2/

http://getbootstrap.com/components/#responsive-embed

【讨论】:

这适用于嵌入视频,但如果我想嵌入一个高度的网页,它会滚动并且高度奇怪。【参考方案9】:

这是一个简单的解决方案,它使用由同一服务器提供的动态生成样式表作为 iframe 内容。很简单,样式表“知道” iframe 中的内容,并且知道用于设置 iframe 样式的尺寸。这绕过了相同的来源政策限制。

http://www.8degrees.co.nz/2010/06/09/dynamically-resize-an-iframe-depending-on-its-content/

所以提供的 iframe 代码会有一个类似的样式表......

<link href="http://your.site/path/to/css?contents_id=1234&dom_id=iframe_widget" rel="stylesheet" type="text/css" />
 <iframe id="iframe_widget" src="http://your.site/path/to/content?content_id=1234" frameborder="0" scrolling="no"></iframe>

这确实需要服务器端逻辑能够计算 iframe 呈现内容的尺寸。

【讨论】:

链接已关闭。您能否在您的答案中分享相关代码,以便它与该线程保持相关?【参考方案10】:

我正在实施 ConroyP 的 frame-in-frame 解决方案来替换基于设置 document.domain 的解决方案,但发现在不同的浏览器中正确确定 iframe 内容的高度非常困难(使用 FF11、Ch17 和IE9)。

ConroyP 用途:

var height = document.body.scrollHeight;

但这仅适用于初始页面加载。我的 iframe 包含动态内容,我需要在某些事件上调整 iframe 的大小。

我最终做的是为不同的浏览器使用不同的 JS 属性。

function getDim () 
    var body = document.body,
        html = document.documentElement;

    var bc = body.clientHeight;
    var bo = body.offsetHeight;
    var bs = body.scrollHeight;
    var hc = html.clientHeight;
    var ho = html.offsetHeight;
    var hs = html.scrollHeight;

    var h = Math.max(bc, bo, bs, hc, hs, ho);

    var bd = getBrowserData();

    // Select height property to use depending on browser
    if (bd.isGecko) 
        // FF 11
        h = hc;
     else if (bd.isChrome) 
        // CH 17
        h = hc;
     else if (bd.isIE) 
        // IE 9
        h = bs;
    

    return h;

getBrowserData() 是由 Ext Core 的http://docs.sencha.com/core/source/Ext.html#method-Ext-apply“启发”的浏览器检测功能@

这在 FF 和 IE 上运行良好,但 Chrome 出现了问题。其中之一是时间问题,显然 Chrome 需要一段时间来设置/检测 iframe 的高度。如果 iframe 高于内容,Chrome 也永远不会正确返回 iframe 中内容的高度。当高度降低时,这不适用于动态内容。

为了解决这个问题,我总是在检测内容高度之前将 iframe 设置为较低的高度,然后将 iframe 高度设置为正确的值。

function resize () 
    // Reset the iframes height to a low value.
    // Otherwise Chrome won't detect the content height of the iframe.
    setIframeHeight(150);

    // Delay getting the dimensions because Chrome needs
    // a few moments to get the correct height.
    setTimeout("getDimAndResize()", 100);

代码未优化,来自我的开发测试:)

希望有人觉得这有帮助!

【讨论】:

【参考方案11】:
<html>
<head>
<script>
function frameSize(id)
var frameHeight;

document.getElementById(id).height=0 + "px";
if(document.getElementById)
    newheight=document.getElementById(id).contentWindow.document.body.scrollHeight;    


document.getElementById(id).height= (frameHeight) + "px";

</script>
</head>

<body>

<iframe id="frame"  src="startframe.html" frameborder="0" margin hspace=20      

onload="javascript:frameSize('frame');">

<p>This will work, but you need to host it on an http server, you can do it locally.    </p>
</body>
</html>

【讨论】:

【参考方案12】:

这是一个旧线程,但在 2020 年它仍然是一个相关问题。我实际上也在另一个旧线程中发布了这个答案^^ (https://***.com/a/64110252/4383587)


只是想分享我的解决方案和兴奋。我花了整整四天的时间进行深入的研究和失败,但我认为我找到了一种让 iframe 完全响应的巧妙方法!耶!

我尝试了很多不同的方法...我不想像postMessage 那样使用双向通信隧道,因为它对于同源来说很尴尬,对于跨域来说很复杂(因为没有管理员想要打开大门并代表您实施)。

我已经尝试使用 MutationObservers,但仍然需要几个 EventListeners(调整大小、单击、..)以确保正确处理布局的每次更改。 - 如果脚本切换元素的可见性怎么办?或者,如果它按需动态​​预加载更多内容呢? - 另一个问题是从某个地方获取 iframe 内容的准确高度。大多数人建议使用scrollHeightoffsetHeight,或者将它们组合使用Math.max。问题是,在 iframe 元素更改其尺寸之前,这些值不会更新。为此,您可以在获取scrollHeight 之前简单地重置iframe.height = 0,但对此还有更多警告。所以,搞砸了。

然后,我有了另一个想法来尝试requestAnimationFrame,以摆脱我的事件和观察者地狱。现在,我可以立即对每个布局更改做出反应,但我仍然没有可靠的来源来推断 iframe 的内容高度。我偶然发现了getComputedStyle!这是一个启示!一切都刚刚好。

好吧,看看我最终可以从无数次尝试中提取的代码。

function fit() 
    var iframes = document.querySelectorAll("iframe.gh-fit")

    for(var id = 0; id < iframes.length; id++) 
        var win = iframes[id].contentWindow
        var doc = win.document
        var html = doc.documentElement
        var body = doc.body
        var ifrm = iframes[id] // or win.frameElement

        if(body) 
            body.style.overflowX = "scroll" // scrollbar-jitter fix
            body.style.overflowY = "hidden"
        
        if(html) 
            html.style.overflowX = "scroll" // scrollbar-jitter fix
            html.style.overflowY = "hidden"
            var style = win.getComputedStyle(html)
            ifrm.width = parseInt(style.getPropertyValue("width")) // round value
            ifrm.height = parseInt(style.getPropertyValue("height"))
        
    

    requestAnimationFrame(fit)


addEventListener("load", requestAnimationFrame.bind(this, fit))

就是这样,是的! - 在您的 HTML 代码中写入&lt;iframe src="page.html" class="gh-fit gh-fullwidth"&gt;&lt;/iframe&gt;gh-fit 是一个假的 CSS 类,用于识别 DOM 中的哪些 iframe 元素应该受脚本影响。 gh-fullwidth 是一个简单的 CSS 类,只有一条规则 width: 100%;

上述脚本会自动从 DOM 中获取所有分配有 .gh-fit 类的 iframe。然后它从document.getComputedStyle(iframe) 中获取并使用预先计算的宽度和高度样式值,这些值始终包含该元素的像素完美大小!!!简直完美!

请注意,此解决方案不能跨域工作(没有任何其他解决方案,没有像 IFrameResizer 这样的双向通信策略)。 JS 根本无法访问不属于您的 iframe 的 DOM。

我能想到的唯一其他跨域解决方案是使用像https://github.com/gnuns/allorigins 这样的代理。但这将涉及深度复制您提出的每个请求 - 换句话说 - 您“窃取”整个页面源代码(使其成为您的并让 JS 访问 DOM)并修补此源中的每个链接/路径,以便它也通过代理。重新链接例程是一个艰难的例程,但可行。

我可能会尝试解决这个跨域问题,但那是另一天的事了。享受代码! :)

【讨论】:

【参考方案13】:

iGoogle 小工具必须主动实现调整大小,所以我的猜测是在跨域模型中,如果没有远程内容以某种方式参与,您将无法做到这一点。如果您的内容可以使用典型的跨域通信技术将新大小的消息发送到容器页面,那么剩下的就很简单了。

【讨论】:

【参考方案14】:

当您想要缩小网页以适应 iframe 大小时:

    您应该调整 iframe 的大小以使其适合内容 那么你应该用加载的网页内容缩小整个 iframe

这是一个例子:

<div id="wrap">
   <IFRAME ID="frame" name="Main" src ="http://www.google.com" />
</div>

<style type="text/css">
    #wrap  width: 130px; height: 130px; padding: 0; overflow: hidden; 
    #frame  width: 900px; height: 600px; border: 1px solid black; 
    #frame  zoom:0.15; -moz-transform:scale(0.15);-moz-transform-origin: 0 0; 
</style>

【讨论】:

【参考方案15】:

这是一个 jQuery 方法,它通过 iframe 的 src 属性在 json 中添加信息。这是一个演示,调整大小并滚动此窗口.. 带有 json 的结果 url 看起来像这样...... http://fiddle.jshell.net/zippyskippy/RJN3G/show/#docHeight:5124,windowHeight:1019,scrollHeight:571#

这里是源代码小提琴http://jsfiddle.net/zippyskippy/RJN3G/

function updateLocation()

    var loc = window.location.href;
    window.location.href = loc.replace(/#.*#/,"") 
        + "#docHeight:"+$(document).height() 
        + ",windowHeight:"+$(window).height()
        + ",scrollHeight:"+$(window).scrollTop()
        +"#";

;

//setInterval(updateLocation,500);

$(window).resize(updateLocation);
$(window).scroll(updateLocation);

【讨论】:

【参考方案16】:

获取 iframe 内容高度,然后将其赋予此 iframe

 var iframes = document.getElementsByTagName("iframe");
 for(var i = 0, len = iframes.length; i<len; i++)
      window.frames[i].onload = function(_i)
           return function()
                     iframes[_i].style.height = window.frames[_i].document.body.scrollHeight + "px";
                     
      (i);
 

【讨论】:

您能否添加一些关于您的代码回答问题的原因的描述?【参考方案17】:

在加载时使用 jquery(跨浏览器):

 <iframe src="your_url" margin  margin scrolling="No" frameborder="0"  hspace="0" vspace="0" id="containiframe" onload="loaderIframe();"   ></iframe>

function loaderIframe()
var heightIframe = $('#containiframe').contents().find('body').height();
$('#frame').css("height", heightFrame);
   

在响应页面中调整大小:

$(window).resize(function()
if($('#containiframe').length !== 0) 
var heightIframe = $('#containiframe').contents().find('body').height();
 $('#frame').css("height", heightFrame);

);

【讨论】:

【参考方案18】:

David Bradshaw 和 Chris Jacob 已经建议使用 postMessage 方法。我完全同意,做这些事情的正确方法。

我只是想发布一个示例,真实有效的代码,以防它成为某些人的现成答案。

在 iframe 端:

<body onload="docResizePipe()">
<script>
var v = 0;
const docResizeObserver = new ResizeObserver(() => 
    docResizePipe();
);
docResizeObserver.observe(document.querySelector("body"));
function docResizePipe() 
    v += 1;
    if (v > 5) 
        return;
    
    var w = document.body.scrollWidth;
    var h = document.body.scrollHeight;
    window.parent.postMessage([w,h], "*");

setInterval(function() 
    v -= 1;
    if (v < 0) 
        v = 0;
    
, 300);
</script>

请注意递归阻塞机制 - 这是必要的,因为 Firefox 中显然存在错误,但无论如何让它存在。

在父文档方面:

<iframe id="rpa-frame" src="3.html" style="border: none;"></iframe>
<script>
var rpaFrame = document.getElementById("rpa-frame");

window.addEventListener("message", (event) => 
    var width = event.data[0];
    var height = event.data[1];
    rpaFrame.width = parseInt(width)+60;
    rpaFrame.height = parseInt(height)+60;
    console.log(event);
, false);
</script>

希望对你有用。

【讨论】:

【参考方案19】:

我在这里阅读了很多答案,但几乎每个人都给出了某种跨域框架块。

示例错误:

Uncaught DOMException: Blocked a frame with origin "null" from 访问跨域框架。

相关帖子中的答案也是如此:

Make iframe automatically adjust height according to the contents without using scrollbar?

我也不想使用像 iFrame Resizer 这样的第三方库或类似的库。

@ChrisJacob 的答案很接近,但我缺少一个完整的工作示例,而不仅仅是链接。 @Selvamani 和 @latitov 也是很好的补充。

https://***.com/a/3219970/3850405

我将width="100%" 用于iframe,但代码也可以修改为使用宽度。

这就是我解决为iframe 设置自定义高度的方法:

内嵌iframe:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="description"
          content="Web site" />
    <title>Test with embedded iframe</title>
</head>
<body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <iframe id="ifrm" src="https://localhost:44335/package/details?key=123" ></iframe>
    <script type="text/javascript">
        window.addEventListener('message', receiveMessage, false);

        function receiveMessage(evt) 
            console.log("Got message: " + JSON.stringify(evt.data) + " from origin: " + evt.origin);
            // Do we trust the sender of this message?
            if (evt.origin !== "https://localhost:44335") 
                return;
            

            if (evt.data.type === "frame-resized") 
                document.getElementById("ifrm").style.height = evt.data.value + "px";
            
        
    </script>
</body>
</html>

iframe source,来自Create React App 的示例,但仅使用了HTMLJS

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="description"
          content="Web site created using create-react-app" />
    <title>React App</title>
</head>
<body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <script type="text/javascript">
        //Don't run unless in an iframe
        if (self !== top) 
            var rootHeight;
            setInterval(function () 
                var rootElement = document.getElementById("root");
                if (rootElement) 
                    var currentRootHeight = rootElement.offsetHeight;
                    //Only send values if height has changed since last time
                    if (rootHeight !== currentRootHeight) 
                        //postMessage to set iframe height
                        window.parent.postMessage( "type": "frame-resized", "value": currentRootHeight , '*');
                        rootHeight = currentRootHeight;
                    
                
            
                , 1000);
        
    </script>
</body>
</html>

setInterval 的代码当然可以修改,但它非常适合动态内容。 setInterval 仅在内容嵌入iframe 时激活,postMessage 仅在高度更改时发送消息。

您可以在此处阅读有关 Window.postMessage() 的更多信息,但该描述非常符合我们想要实现的目标:

window.postMessage() 方法可以安全地启用跨域 Window 对象之间的通信;例如,在一个页面和一个 它产生的弹出窗口,或在页面和嵌入的 iframe 之间 在里面。

通常情况下,不同页面上的脚本是允许相互访问的 当且仅当它们源自的页面共享相同的协议, 端口号和主机(也称为“同源策略”)。 window.postMessage() 提供了一种受控机制来安全地 绕过这个限制(如果使用得当)。

https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage

【讨论】:

【参考方案20】:

如果您可以控制 iframe 内容,我强烈建议您使用

ResizeObserver

只需在iframesrcdoc 属性末尾插入以下内容, escape如果需要的话。

<script type="text/javascript">
var ro = new ResizeObserver(entries => 
  for (let entry of entries) 
    const cr = entry.contentRect;
    // console.log(window.frameElement);
    window.frameElement.style.height =cr.height +30+ "px";
  
);

ro.observe(document.body);
</script>

【讨论】:

【参考方案21】:

https://getbootstrap.com/docs/4.0/utilities/embed/

经过大量研究,我恍然大悟,这不是一个独特的问题,我敢打赌 Bootstrap 会处理它。你瞧……

【讨论】:

【参考方案22】:

使用 jQuery:

父.html

<body>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<style>
iframe 
    width: 100%;
    border: 1px solid black;

</style>
<script>
function foo(w, h) 
    $("iframe").css(width: w, height: h);
    return true;  // for debug purposes

</script>
<iframe src="child.html"></iframe>
</body>

child.html

<body>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script>
$(function() 
    var w = $("#container").css("width");
    var h = $("#container").css("height");

    var req = parent.foo(w, h);
    console.log(req); // for debug purposes
);
</script>
<style>
body, html 
    margin: 0;

#container 
    width: 500px;
    height: 500px;
    background-color: red;

</style>
<div id="container"></div>
</body>

【讨论】:

【参考方案23】:

找不到可以完美处理大文本 + 大图像的东西,但我最终得到了这个,似乎每次都正确或几乎正确:

    iframe.addEventListener("load",function()
        // inlineSize, length, perspectiveOrigin, width
        let heightMax = 0;
        // this seems to work best with images...
        heightMax = Math.max(heightMax,iframe.contentWindow.getComputedStyle(iframe.contentWindow.document.body).perspectiveOrigin.split("px")[0]);
        // this seems to work best with text...
        heightMax = Math.max(heightMax,iframe.contentWindow.document.body.scrollHeight);
        // some large 1920x1080 images always gets a little bit off on firefox =/
        const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
        if(isFirefox && heightMax >= 900)
            // grrr..
            heightMax = heightMax + 100;
        

        iframe.style.height = heightMax+"px";
        //console.log(heightMax);
    );

【讨论】:

【参考方案24】:

这有点棘手,因为您必须知道 iframe 页面何时加载,当您无法控制其内容时,这很困难。可以将 onload 处理程序添加到 iframe,但我过去曾尝试过,并且它在浏览器中的行为有很大不同(不知道谁是最烦人的......)。您可能必须向 iframe 页面添加一个函数来执行调整大小并将一些脚本注入到内容中,以监听加载事件或调整大小事件,然后调用前一个函数。我正在考虑向页面添加一个功能,因为您想确保它的安全,但我不知道这样做会有多容易。

【讨论】:

【参考方案25】:

我相信这样的东西应该可以工作。

parent.document.getElementById(iFrameID).style.height=framedPage.scrollHeight;

在 iframe 内容上加载你的 body onload。

【讨论】:

这是不可能的,因为 iFrame 中的内容是从其他域加载的,因此尝试这样做会导致错误,例如来自 Firefox:“Permission denied to get property Window.document” .【参考方案26】:

我有一个简单的解决方案,需要您确定链接中的宽度和高度,请尝试(适用于大多数浏览器):

<a href='#' onClick=" document.getElementById('myform').src='t2.htm';document.getElementById('myform').width='500px'; document.getElementById('myform').height='400px'; return false">500x400</a>

【讨论】:

以上是关于根据内容调整 iframe 的大小的主要内容,如果未能解决你的问题,请参考以下文章

仅在 Chrome 中调整 iframe 大小问题

怎么让iframe的大小跟随内容的大小自动调整?

跨域 iframe 调整大小?

为 iframe 内容调整 jQuery 颜色框的大小?

调整外部网站内容的大小以适合 iFrame 宽度

将 iframe 内容高度设置为动态自动调整大小