调整iframe的宽度和高度以适应其中的内容

420

我需要一个解决方案来自动调整iframe宽度高度,以便刚好适合其内容。关键是,在iframe加载后,宽度高度可能会发生变化。我猜我需要一个事件操作来处理iframe中包含的正文尺寸的变化。


Angular iFrame自适应高度:https://gitlab.com/reduardo7/angular-iframe-auto-height - Eduardo Cuomo
已接受的答案无效,请尝试 https://dev59.com/6XRA5IYBdhLWcg3wzhRY#31513163。 - Steven Shaw
https://getbootstrap.com/docs/4.0/utilities/embed/经过大量的研究,我意识到这不是一个独特的问题,我打赌Bootstrap可以处理它。果然... - AZ Chad
如果您控制iframe源,则很幸运,下面建议的解决方案可能有效,或者您可以尝试像https://github.com/davidjbradshaw/iframe-resizer这样的东西。如果您的用例具有您无法控制的iframe源,则没有解决方案,至少我找不到。 - akshay
35个回答

322
<script type="application/javascript">

function resizeIFrameToFitContent( iFrame ) {

    iFrame.width  = iFrame.contentWindow.document.body.scrollWidth;
    iFrame.height = iFrame.contentWindow.document.body.scrollHeight;
}

window.addEventListener('DOMContentLoaded', function(e) {

    var iFrame = document.getElementById( 'iFrame1' );
    resizeIFrameToFitContent( iFrame );

    // or, to resize all iframes:
    var iframes = document.querySelectorAll("iframe");
    for( var i = 0; i < iframes.length; i++) {
        resizeIFrameToFitContent( iframes[i] );
    }
} );

</script>

<iframe src="usagelogs/default.aspx" id="iFrame1"></iframe>

9
@StoneHeart:是的,它可以跨浏览器使用。该代码不符合标准,因为它使用了contentWindow属性,而该属性在DOM规范中并未定义。在DOM规范中存在一个名为contentDocument的属性,但是Internet Explorer 6(和7?)不支持它。可以使用contentWindow属性代替,并且在所有常见的浏览器(Gecko、Opera、Webkit、IE)中都实现了它。 - Rafael
31
如果(document.getElementById)有什么用? - Ally
71
请注意,它不是跨域的。如果域名不同,则会出现“_Error: Permission denied to access property 'document'_”这种错误。可以在此处找到解决方案。 - Pierre de LESPINAY
15
条件语句不仅是无用的,而且在它所预期的罕见情况下肯定会引起问题。你为什么要检查方法是否存在,然后在检查之外使用该方法? - J S
6
我认为你的意思是 DOMContentLoaded,因为似乎没有 DOMContentReady 这个东西:https://developer.mozilla.org/en-US/search?q=domcontentready&topic=apps&topic=html&topic=css&topic=js&topic=api&topic=webdev - Max Heiber
显示剩余21条评论

76

一种嵌入式的单行解决方案:从最小大小开始增加到内容大小。无需脚本标签。

<iframe src="http://URL_HERE.html" onload='javascript:(function(o){o.style.height=o.contentWindow.document.body.scrollHeight+"px";}(this));' style="height:200px;width:100%;border:none;overflow:hidden;"></iframe>


运行代码片段在Safari 9.1.1上无法工作,可能包含SO问题? - Elensar
4
这不涉及跨域问题。也许服务器需要为嵌入页面添加一些标头(header)? - Finesse
2
所有在此处提到 scrollHeight/scrollWidth 的答案都应该稍微调整一下,以考虑到 body 边距的影响。浏览器为文档的 body 元素(以及加载到框架中的内容)应用默认的非零边距。我找到的解决方案是添加以下代码:parseInt(window.getComputedStyle(this.contentDocument.body).margin - Stan
@Stan,文档内可能存在具有大于body边距的元素,这也没有在您的解决方案中加以考虑。 - Bouke
@Stan 使用 body.parentElement.scrollHeight 替代 body.scrollHeight(宽度同理),这样就可以包括文档边距等内容。如果使用 body,则会排除顶级 html 元素的边距/填充。 - Jason C
3
今天在任何浏览器中都无法使用上述解决方案或上面的解决方案。 - WilliamK

56

跨浏览器的jQuery插件

跨域名、跨浏览器的,使用mutationObserver来保持iFrame与内容大小相同,并且使用postMessage在iFrame和宿主页面之间进行通信。可以与jQuery配合使用,也可以单独使用。


8
iframe-resizer 库是最强大的解决方案。 - kwill

37
到目前为止,给出的所有解决方案都只考虑了一次性的调整大小。你提到你想在修改内容后能够调整 iFrame 的大小。为了做到这一点,你需要在 iFrame 内执行一个函数(一旦内容被改变,你需要触发一个事件来表明内容已经改变)。
我曾经困扰于此,因为 iFrame 内部的代码似乎仅限于 iFrame 内部的 DOM(无法编辑 iFrame),而在 iFrame 外部执行的代码则被困在 iFrame 外部的 DOM 中(无法接收来自 iFrame 内部的事件)。
解决方案是通过发现(在同事的帮助下)jQuery 可以告诉它要使用哪个 DOM 来实现的。在这种情况下,父窗口的 DOM。
因此,像这样在 iFrame 中运行的代码可以实现你所需的功能:
<script type="text/javascript">
    jQuery(document).ready(function () {
        jQuery("#IDofControlFiringResizeEvent").click(function () {
            var frame = $('#IDofiframeInMainWindow', window.parent.document);
            var height = jQuery("#IDofContainerInsideiFrame").height();
            frame.height(height + 15);
        });
    });
</script>

这个的完整代码是什么?我猜脚本放在iframe的HTML里面? - Andrew Hundt
这是完整的代码,并且可以在iFrame的HTML中运行。"window.parent.document"的部分指定jQuery选择器应该使用父文档的DOM,而不是您所在的文档(即在iFrame内部)。 - Garnaph
16
如果父文档和 iframe 中的文档来自同一域,则此方法效果良好。如果它们不是来自同一域(或在 Chrome 中,如果它们都是本地文件),那么浏览器的“同源”安全策略会生效,并阻止 iframe 内容修改父文档。 - user56reinstatemonica8
1
对于任何试图在跨域环境下实现类似功能的人,请查看 window.postMessage(IE8+),并注意您需要在主机(父级)和源(iframe内部)文档上使用自定义脚本。jQuery postmessage插件可能会有所帮助。由于您需要在主机和源上使用脚本,因此最简单的方法可能是通过使用JSON-P使用AJAX加载内容。 - user56reinstatemonica8
4
如何自动触发事件而不是使用jQuery("#IDofControlFiringResizeEvent").click(function () - Ben

31
如果iframe的内容来自相同的域名,这将非常有效。但是需要使用jQuery。
$('#iframe_id').load(function () {
    $(this).height($(this).contents().height());
    $(this).width($(this).contents().width());
});

要使其动态调整大小,您可以这样做:

<script language="javaScript">
<!--
function autoResize(){
    $('#themeframe').height($('#themeframe').contents().height());
}
//-->
</script>
<iframe id="themeframe" onLoad="autoResize();" marginheight="0" frameborder="0" src="URL"></iframe>

然后在iframe加载的页面上添加以下内容:

<script language="javaScript">
function resize()
{
    window.parent.autoResize();
}

$(window).on('resize', resize);
</script>

1
当来源于不同域时,有没有简单的方法来做到这一点? - BruceJohnJennerLawso
这在 jQuery 3.6.0 上返回错误。 - Loenix

16

如果您不想使用jQuery,这里有一个跨浏览器的解决方案:

/**
 * Resizes the given iFrame width so it fits its content
 * @param e The iframe to resize
 */
function resizeIframeWidth(e){
    // Set width of iframe according to its content
    if (e.Document && e.Document.body.scrollWidth) //ie5+ syntax
        e.width = e.contentWindow.document.body.scrollWidth;
    else if (e.contentDocument && e.contentDocument.body.scrollWidth) //ns6+ & opera syntax
        e.width = e.contentDocument.body.scrollWidth + 35;
    else (e.contentDocument && e.contentDocument.body.offsetWidth) //standards compliant syntax – ie8
        e.width = e.contentDocument.body.offsetWidth + 35;
}

1
很奇怪,对我来说它计算出了非常奇怪的iframe宽度。内容宽度为750,但它将其计算为300。您有什么想法为什么会这样吗? - Rob
我尝试了这段代码(加入高度选项)。如果我将iFrame高度设置为100%,它会限制为约200像素。如果我将iFrame高度设为600像素,它将保持在那个高度。@RobertJagoda,你解决了这个问题吗? - iaindownie

10

在我尝试了地球上的一切之后,这真的对我有用。

index.html

<style type="text/css">
html, body{
  width:100%;
  height:100%;
  overflow:hidden;
  margin:0px;   
}
</style>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
function autoResize(iframe) {
    $(iframe).height($(iframe).contents().find('html').height());
}
</script>

<iframe src="http://iframe.domain.com" width="100%" height="100%" marginheight="0" frameborder="0" border="0" scrolling="auto" onload="autoResize(this);"></iframe>

未捕获的类型错误:$ 不是一个函数 在 autoResize ((index):200) 在 HTMLIFrameElement.onload ((index):204) - Michael Rogers
2
@Michael Rogers,您的代码中存在$符号冲突或者忘记引入jQuery.js文件。请使用通用函数https://dev59.com/om025IYBdhLWcg3wRTtK或将$替换为jQuery。 - Adrian P.
看起来我需要一个星际解决方案,因为这个不起作用。 - user3035649

9

背景

我在一个Web扩展程序中自己实现了这个功能。这个Web扩展会在每个页面中注入一些UI,这些UI位于一个iframe内部。iframe内的内容是动态的,因此我必须重新调整iframe本身的宽度和高度。

我使用了React,但这个概念适用于所有库。

我的解决方案(假设您控制页面和iframe

iframe内部,我更改了body样式,使其具有非常大的尺寸。这将使内部元素使用所有必要的空间进行布局。将widthheight设置为100%对我来说不起作用(我猜是因为iframe具有默认的width = 300pxheight = 150px

/* something like this */
body {
  width: 99999px;
  height: 99999px;
}

然后我将所有iframe UI注入到一个div中,并对其进行了一些样式设置。

#ui-root {
  display: 'inline-block';     
}

在我的应用程序中,我使用 React#ui-root 内部进行渲染(我在 componentDidMount 中执行此操作)。然后,我计算此 div 的尺寸,并使用 window.postMessage 将其与父页面同步:

let elRect = el.getBoundingClientRect()
window.parent.postMessage({
  type: 'resize-iframe',
  payload: {
    width: elRect.width,
    height: elRect.height
  }
}, '*')

在父框架中,我会做如下操作:
window.addEventListener('message', (ev) => {
  if(ev.data.type && ev.data.type === 'resize-iframe') {
    iframe.style.width = ev.data.payload.width + 'px'
    iframe.style.height = ev.data.payload.height + 'px'
  }
}, false)

8

我正在使用这段代码来自动调整页面上所有带有“autoHeight”类的iframe的高度。经过测试,在IE、FF、Chrome、Safari和Opera中均可正常工作。

function doIframe() {
    var $iframes = $("iframe.autoHeight"); 
    $iframes.each(function() {
        var iframe = this;
        $(iframe).load(function() {
            setHeight(iframe);
        });
    });
}

function setHeight(e) {
  e.height = e.contentWindow.document.body.scrollHeight + 35;
}

$(window).load(function() {
    doIframe();
});

2
你添加的这个神奇的35是什么意思?你是在哪个浏览器和操作系统上进行的测量? - h2stein
现在我真的不知道为什么我添加了35个像素。但我可以肯定地告诉你,我在FF、IE(7、8、9)和Chrome上进行了测试,它完全正常工作。 - petriq
3
我认为35只是滚动条的厚度。 - Sadegh
我不得不稍微调整一下才能让它工作 - 直接调用setHeight(iframe);(删除了$(iframe).load()包装器)。 - shacker
增加的神奇35像素是为了考虑到iframe填充。我想要补充的是,iframe不应该包含填充,iframe的内容应该自行处理这个问题。 - Filipe Melo

6
这是一个可靠的证明解决方案。
function resizer(id)
{

var doc=document.getElementById(id).contentWindow.document;
var body_ = doc.body, html_ = doc.documentElement;

var height = Math.max( body_.scrollHeight, body_.offsetHeight, html_.clientHeight, html_.scrollHeight, html_.offsetHeight );
var width  = Math.max( body_.scrollWidth, body_.offsetWidth, html_.clientWidth, html_.scrollWidth, html_.offsetWidth );

document.getElementById(id).style.height=height;
document.getElementById(id).style.width=width;

}

the html

<IFRAME SRC="blah.php" id="iframe1"  onLoad="resizer('iframe1');"></iframe>

1
首先感谢您发布这篇文章已经有很长一段时间了。但是,在您的最后两个指令中缺少字符串值“px”,需要添加才能使其正常工作 :)document.getElementById(id).style.height=height + "px"; document.getElementById(id).style.width=width + "px"; - Foxlab

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接