根据内容调整iframe的大小


498

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

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

我试图破译Google使用的javascript,但是它被混淆了,到目前为止,在网络上搜索是徒劳的。

更新:请注意,内容是从其他域加载的,因此适用同源策略

Answers:


584

我们遇到了这类问题,但与您的情况略有不同-我们向其他域上的网站提供了iframed内容,因此相同的来源政策也是一个问题。经过数小时的拖曳Google搜寻,我们最终找到了(某种程度上..)可行的解决方案,您也许可以适应您的需求。

有一种方法可以绕过相同的原始策略,但是它需要同时在iframed内容和框架页面上进行更改,因此,如果您无法在两边都请求更改,则此方法对您将不会很有用,我耽心。

有一个浏览器怪癖,它使我们可以略过相同的原始策略-javascript可以与其自身域上的页面通信,也可以与其已被iframed的页面通信,但是不能与包含该页面的页面进行通信,例如,如果您具有:

 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(iframe)发送邮件,但不能 home.html(子级无法与父级进行跨域通信)发送邮件。

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

因此,从本质上讲,在framed.html加载时,它会计算出自己的高度,tells helper.html会将消息传递到home.html,然后可以调整其所在iframe的大小framed.html

我们发现,从传递消息最简单的方法framed.htmlhelper.html是通过URL参数。为此,请指定framed.html一个iframe src=''。当它的onload火灾,它评估了自己的高度,并设置了iframe的src在这一点上helper.html?height=N

这里有一个关于Facebook如何处理它的解释,这可能比上面的我的解释更清楚!


在中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>

7
充满洞察力。我想知道为什么igoogle.com上有一个helper.html文件!谢谢
IEnumerator

9
很好,谢谢!我做了一些补充:使用jQuery在framed.html中获取主体高度(FF问题,主体不断增长):var height = $(document.body).height(); 使用body onload事件在home.html中创建框架,类似于在framed.html中使用的方法。地址未在FF和Safari中刷新时更新框架。
2009年

5
天才!除了Abdullah的其他功能:parentIframeResize()我没有使用body来调用on ,而是使用JQuery来捕获页面加载和任何大小调整事件:$(document).ready(iframeResizePipe); $(window).resize(iframeResizePipe);这允许我设置iframe width="100%",如果窗口宽度发生变化以进行自动换行或其他操作,内框会意识到它需要调整大小。
StriplingWarrior 2010年

9
我建议为iframe id = frame_name_here提供默认的高度属性,例如height =“ 2000”。这意味着当页面加载时,框架内容可见。调整大小时,没有“闪烁”。调整大小在页面折叠下方缩小/扩展。如果您知道iframed内容的最大高度,请使用该值...这也可以带来更好的noscript体验。
克里斯·雅各布

3
七年后,仍然是我发现的最好的跨浏览器,跨域解决方案。太棒了
FurryWombat

81

如果您不需要处理来自其他域的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" width="100%" height="200px" id="iframe1" marginheight="0" frameborder="0" onLoad="autoResize('iframe1');"></iframe>

9
最好将元素本身传递给函数,以避免所有这些document.getElementById(id)并简化代码。
Muhd

1
这对我不起作用,因为contentWindow.document.body.scrollHeight保持0而不是实际高度。
kroiz 2011年

4
与我尝试过的所有其他解决方案一样,此解决方案仅在高度增加时才有效,如果从较高的页面导航到较短的页面,则仍然根据第一个页面的高度设置高度。有人找到这个问题的解决方案吗?
Eugenio

6
@Eugenio和包括我在内的每个人都可以解决这个最后的问题:请访问stackoverflow.com/questions/3053072/… 在要求iframe内的文档高度之前,应将iframe对象的高度设置为“自动”。请注意,您应该使用style.height而不是像上面的答案中那样的高度
Kyle

7
我不明白...您检查document.getElementById是否存在,然后在检查区域之外调用它?
莱戈拉斯

41

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

window.postMessage()

window.postMessage是一种用于安全启用跨域通信的方法。通常,仅当且仅当执行脚本的页面位于具有相同协议(通常为http),端口号(http的默认值为80)和主机(模数)的位置时,才允许访问其他页面上的脚本。两个页面都将document.domain设置为相同的值)。window.postMessage提供了一种受控机制,可以在适当使用时以安全的方式规避此限制。

摘要

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

iframe的调整器库使用的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栏的“垃圾”。
爱马仕(Herms)

2
postMessage似乎是X浏览器。只有IE才有bug或需要注意的事情:1.仅在框架或iframe之间进行通信2.仅能够发布字符串。参见:caniuse.com/x-doc-messaging
Christian Kuetbach 2013年

3
很高兴看到您回答问题,而不是解释有关有助于解决问题的辅助技术
。.– hitautodestruct

periscopedata正在使用postMessage,如果对他们足够好,那么对我们也足够。这是他们的文档:doc.periscopedata.com/docv2/embed-api-options
Yevgeniy Afanasyev

8

使用jQuery的最简单方法:

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

14
不跨域请求。
willem

6

http://www.phinesolutions.com/use-jquery-to-adjust-the-if​​rame-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上已经具有“ height”属性,则只会添加style =“ height:xxx”。这可能不是您想要的。


7
没有跨网域,没有。
Volomike 2010年

正是我所需要的,因为我没有进行跨域的操作,为有效的html +1。
WildJoe 2011年

4

可能有点晚了,因为所有其他答案都比较老了:-)但是...这是我的解决方案。在实际的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%)。
pashute

4

最后,我找到了其他一些解决方案,可以使用以下方法从iframe将数据发送到父网站: window.postMessage(message, targetOrigin);。在这里,我解释了我的工作方式。

网站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 (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);

2

这是一个简单的解决方案,它使用由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" width="100%" scrolling="no"></iframe>

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


链接已断开。您能否在答案中共享相关代码,以使其与该线程保持相关性?
zed

2

此答案仅适用于使用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/#sensitive-embed


这适用于嵌入视频,但是如果我想嵌入一个具有一定高度的网页,它会滚动并出现一个怪异的高度。
cabaji99

1

我正在实施ConroyP的帧内解决方案来替换基于设置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);
}

代码没有经过优化,来自我的开发测试:)

希望有人觉得这有帮助!


1
<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" marginheight="0" hspace=20     width="100%" 

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>

0

iGoogle小工具必须积极实现调整大小,因此我的猜测是在跨域模型中,如果没有远程内容参与某种方式,您将无法做到这一点。如果您的内容可以使用典型的跨域通信技术将新大小的消息发送到容器页面,则其余的操作很简单。


0

当您要缩小网页以使其适合iframe大小时:

  1. 您应该调整iframe的大小以使其适合内容
  2. 然后,您应该使用加载的网页内容缩小整个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>

0

这是一种通过iframe的src属性在json中添加信息的jQuery方法。这是一个演示,调整大小并滚动此窗口。.带有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);

0

获取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);
 }

1
您能否添加一些有关您的代码为何回答问题的描述?
2013年

0

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

 <iframe src="your_url" marginwidth="0"  marginheight="0" scrolling="No" frameborder="0"  hspace="0" vspace="0" id="containiframe" onload="loaderIframe();" height="100%"  width="100%"></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);
}
});

-1

使用jQuery:

parent.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>

-2

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


-2

我相信这件事应该起作用。

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

在iframe内容上,将其加载到身体上。


3
这是不可能的,因为iFrame中的内容是从其他域加载的,因此尝试执行此操作会导致错误,例如Firefox中的错误:“权限被拒绝获取属性Window.document”。
larssg

-4

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

<a href='#' onClick=" document.getElementById('myform').src='t2.htm';document.getElementById('myform').width='500px'; document.getElementById('myform').height='400px'; return false">500x400</a>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.