268

I am loading an aspx web page in an iframe. The content in the Iframe can be of more height than the iframe's height. The iframe should not have scroll bars.

I have a wrapper div tag inside the iframe which basically is all the content. I wrote some jQuery to make the resize happen :

$("#TB_window", window.parent.document).height($("body").height() + 50);

where TB_window is the div in which the Iframe is contained.

body - the body tag of the aspx in the iframe.

This script is attached to the iframe content. I am getting the TB_window element from the parent page. While this works fine on Chrome, but the TB_window collapses in Firefox. I am really confused/lost on why that happens.

L84
  • 45,514
  • 58
  • 177
  • 257
karry
  • 3,270
  • 3
  • 18
  • 31

24 Answers24

245

You can retrieve the height of the IFRAME's content by using: contentWindow.document.body.scrollHeight

After the IFRAME is loaded, you can then change the height by doing the following:

<script type="text/javascript">
  function iframeLoaded() {
      var iFrameID = document.getElementById('idIframe');
      if(iFrameID) {
            // here you can make the height, I delete it first, then I make it again
            iFrameID.height = "";
            iFrameID.height = iFrameID.contentWindow.document.body.scrollHeight + "px";
      }   
  }
</script>   

Then, on the IFRAME tag, you hook up the handler like this:

<iframe id="idIframe" onload="iframeLoaded()" ...

I had a situation a while ago where I additionally needed to call iframeLoaded from the IFRAME itself after a form-submission occurred within. You can accomplish that by doing the following within the IFRAME's content scripts:

parent.iframeLoaded();
Aristos
  • 66,005
  • 16
  • 114
  • 150
  • should the above script be attached to the parent window or the Iframe? – karry Feb 06 '12 at 16:44
  • 1
    @karry as it is to the parent. The trick is the scrollHeight here – Aristos Feb 06 '12 at 17:05
  • 210
    It doesn't support on Cross Domain. – Soumya Feb 24 '13 at 06:19
  • 4
    @Soumya The cross domain have nothing to do with this code. There is a security issue that you bypass with a command. – Aristos Feb 24 '13 at 07:44
  • @Aristos. That is why I said as this code is not suitable if Cross Domain issue appeared. Right now I am facing one and literally tearing my hairs to solve the issue. All the time getting Permission denied on access property.....(Everything including document,documentElement etc) – Soumya Feb 24 '13 at 07:49
  • 9
    @Soumya Look for the `X-FRAME-OPTIONS` to add a line as: `Response.AddHeader("X-FRAME-OPTIONS", "SAMEORIGIN");` or `response.addHeader("X-FRAME-OPTIONS", "Allow-From https://some.othersite.com");` – Aristos Feb 24 '13 at 07:56
  • I agree with Kenton! I've been wanting to do something like this FOR YEARS!!! AWESOME, THANKS!!! – Rocco The Taco Mar 28 '14 at 17:32
  • @Prodac Place this code `iframeLoaded` on the main window, not inside the iframe – Aristos Apr 02 '14 at 15:10
  • 1
    @Aristos In main window, on the iFrame, like – iamchriswick Apr 02 '14 at 15:33
  • @Prodac add there and the full iframeloaded function inside `` somewhere on body – Aristos Apr 02 '14 at 16:32
  • 18
    This solves the cross domain iframe sizing issue https://github.com/davidjbradshaw/iframe-resizer – David Bradshaw Apr 10 '14 at 20:07
  • @DavidBradshaw Thank you for the link/reference, please leave your comment here as reference to this link. – Aristos Apr 10 '14 at 23:39
  • 2
    @DavidBradshaw - nice script you have in there, it might work even cross-domain but the most use scenario with CORS is when you don't have access to the remote loaded page. I was trying your script for loading a google docs form into a website (embedded) which doesn't do the trick ;( – qdev Mar 24 '15 at 09:18
  • @qdev google sites have many anti-copy/anti-frame mechanisms. The only way to work with google is to use the google api and go from the path that google provides. – Aristos Mar 24 '15 at 18:57
  • @DavidBradshaw would love to see your comment as an answer here. – AllInOne Jun 02 '15 at 19:58
  • This code is amazing. I spent almost an hour looking for this code. This belongs on a jsfiddle or codepen. Wonderful solution! – www139 Sep 14 '15 at 04:14
  • You may need to use setTimeout, without it, it was calculating the wrong height. – Andrew WC Brown Oct 06 '15 at 19:51
  • @AndrewWCBrown Nice idea, you can use timeout if the iframe make update of some kind of difficult page - if the page is simple this is still work. – Aristos Oct 07 '15 at 06:26
  • maybe it's just me, but it seems that if the height is below 150px it sets that as the minimum height. Is there a reason for that? I'm trying to do this for a one liner (minimum) – deebs Aug 19 '16 at 20:39
  • I had to use .offsetHeight instead of .scrollHeight... I only had one or two lines in the iframe, so the scrollHeight seemed to calculate a minimum of 150px which was still too large. – deebs Aug 22 '16 at 14:01
  • 2
    @deebs You could also try changing `iFrameID.height = "";` to `iFrameID.height = "20px";`. The default browser iframe height is 150px which is what `""` resets it back to. – philfreo Oct 04 '16 at 15:49
  • This doesnt work with items that "roll up" e.g datatables or floating div's. The height is based on whatever the normal unrolled-up height would be and not the final height. – djack109 Oct 12 '16 at 04:01
  • @djack109 Apparently can not work, but you can use that idea and make it grow up... – Aristos Oct 12 '16 at 07:33
136

A slightly improved answer to Aristos...

<script type="text/javascript">
  function resizeIframe(iframe) {
    iframe.height = iframe.contentWindow.document.body.scrollHeight + "px";
  }
</script>  

Then declare in your iframe as follows:

<iframe onload="resizeIframe(this)" ...

There are two minor improvements:

  1. You don't need to get the element via document.getElementById - as you already have it in the onload callback.
  2. There's no need to set the iframe.height = "" if you're going to reassign it in the very next statement. Doing so actually incurs an overhead as you're dealing with a DOM element.

Edit: If the content in the frame is always changing then call:

parent.resizeIframe(this.frameElement); 

from within the iframe after the update. Works for same origin.

Or to auto detect:

  // on resize
  this.container = this.frameElement.contentWindow.document.body;

  this.watch = () => {
    cancelAnimationFrame(this.watcher);

    if (this.lastScrollHeight !== container.scrollHeight) {
      parent.resizeIframeToContentSize(this.frameElement);  
    }
    this.lastScrollHeight = container.scrollHeight;
    this.watcher = requestAnimationFrame(this.watch);
  };
  this.watcher = window.requestAnimationFrame(this.watch);
eddyparkinson
  • 3,680
  • 4
  • 26
  • 52
BlueFish
  • 5,045
  • 3
  • 26
  • 35
  • 7
    What would you do if the content in the frame is always changing? – Kevin May 13 '13 at 14:26
  • If the content size keeps changing and/or if your iframe is designed to sit on other domains other than the domain the iframe pulls the page from, then you will need to do something different. – BlueFish May 13 '13 at 23:13
  • 5
    For this... the solution is to use postMessage and receiveMessage. I solved this using https://github.com/jeffomatic/nojquery-postmessage – BlueFish May 13 '13 at 23:13
  • 1
    The idea is to calculate the new height and send a message to the parent frame which needs to receive the message and adjust the iframe's height accordingly. – BlueFish May 13 '13 at 23:15
  • It was always some Pixels short for me, so I came up with this: `function resizeIframe(iframe) { var size=iframe.contentWindow.document.body.scrollHeight; var size_new=size+20; iframe.height = size_new + "px"; }` – Martin Muehl Dec 14 '13 at 15:20
  • I had to add this first, inside the function, for it to work: iframe.height = ''; – Will Peavy Oct 02 '15 at 16:12
  • If anyone can figure out how to resize whenever the content changes, that would be Useful :D. WIthout just doing an interval... – Andrew Feb 05 '16 at 20:38
  • 1
    I believe the `iFrameID.height = "";` (or setting it to '20px' instead) is necessary if you ever need `resizeIframe` to make an iframe smaller than it currently is. For example, if you trigger this upon parent window resize, if the window & iframe gets wider and you want the iframe to shrink height as a result, you need that line. It's necessary because `iframe.contentWindow.document.body.scrollHeight` is only accurate if the iframe is currently sized _smaller_ than the required content height. – philfreo Oct 04 '16 at 15:56
  • Might be helpful for you want to hide the scrollbars on iframe but also get the height on load: `iframe.height = iframe.contentWindow.document.body.scrollHeight + "px"; iframe.contentWindow.document.querySelector("html").style.overflow = "hidden";` – John Feb 23 '18 at 12:23
  • @Kevin after resize of frame call parent.resizeIframe(this.frameElement); .. worked for me. – eddyparkinson Aug 29 '19 at 08:04
  • Not cross-domain. I get `Uncaught DOMException: Permission denied to access property "document" on cross-origin object` – Fanky Mar 16 '21 at 08:59
  • More accurate way to obtain the height, thanks. `function resizeIframe(iframe) { var doc = iframe.contentWindow.document; var height = Math.max( doc.body.scrollHeight, doc.documentElement.scrollHeight, doc.body.offsetHeight, doc.documentElement.offsetHeight, doc.body.clientHeight, doc.documentElement.clientHeight ); iframe.height = height; }` – Sunding Wei Mar 19 '21 at 02:22
  • I found this works if the iframe is defined with height= property directly, but not if the initial height is declared in the style= property. Because I found a certain browser was not following the script I was ending up with an iframe that had 0 height, so setting an initial height was needed. – Veggiet Jan 13 '22 at 21:18
76

I found that the accepted answer didn't suffice, since X-FRAME-OPTIONS: Allow-From isn't supported in safari or chrome. Went with a different approach instead, found in a presentation given by Ben Vinegar from Disqus. The idea is to add an event listener to the parent window, and then inside the iframe, use window.postMessage to send an event to the parent telling it to do something (resize the iframe).

So in the parent document, add an event listener:

window.addEventListener('message', function(e) {
  var $iframe = jQuery("#myIframe");
  var eventName = e.data[0];
  var data = e.data[1];
  switch(eventName) {
    case 'setHeight':
      $iframe.height(data);
      break;
  }
}, false);

And inside the iframe, write a function to post the message:

function resize() {
  var height = document.getElementsByTagName("html")[0].scrollHeight;
  window.parent.postMessage(["setHeight", height], "*"); 
}

Finally, inside the iframe, add an onLoad to the body tag to fire the resize function:

<body onLoad="resize();">
Marty Mulligan
  • 1,134
  • 7
  • 9
  • 1
    In order for this to work for me I had to change "window.parent" to just "parent". – prograhammer Aug 20 '14 at 18:29
  • 2
    Great! but it only loads the height once. If you want to make the iframe truly responsive I prefer to call the resize method every second, like this: `setInterval(resize, 1000);` – Jules Colle Apr 06 '19 at 15:04
  • 3
    good solution, no cross site scripting error. – Joel Jun 06 '22 at 06:57
16

Add this to the iframe, this worked for me:

onload="this.height=this.contentWindow.document.body.scrollHeight;"

And if you use jQuery try this code:

onload="$(this).height($(this.contentWindow.document.body).find(\'div\').first().height());"
Mohit Aneja
  • 428
  • 4
  • 11
7

you could also add a repeating requestAnimationFrame to your resizeIframe (e.g. from @BlueFish's answer) which would always be called before the browser paints the layout and you could update the height of the iframe when its content have changed their heights. e.g. input forms, lazy loaded content etc.

<script type="text/javascript">
  function resizeIframe(iframe) {
    iframe.height = iframe.contentWindow.document.body.scrollHeight + "px";
    window.requestAnimationFrame(() => resizeIframe(iframe));
  }
</script>  

<iframe onload="resizeIframe(this)" ...

your callback should be fast enough to have no big impact on your overall performance

mbehzad
  • 3,758
  • 3
  • 22
  • 29
  • 1
    this is a very slick solution that, from initial testing, works very well. I would be interested in the performance implications of using this. – KFE Feb 27 '19 at 17:36
  • Just ran into a case `Uncaught TypeError: Cannot read property 'scrollHeight' of null` since `body` is `null`, however it works usually. – caot Nov 14 '19 at 14:13
6

There are four different properties you can look at to get the height of the content in an iFrame.

document.documentElement.scrollHeight
document.documentElement.offsetHeight
document.body.scrollHeight
document.body.offsetHeight

Sadly they can all give different answers and these are inconsistant between browsers. If you set the body margin to 0 then the document.body.offsetHeight gives the best answer. To get the correct value try this function; which is taken from the iframe-resizer library that also looks after keeping the iFrame the correct size when the content changes,or the browser is resized.

function getIFrameHeight(){
    function getComputedBodyStyle(prop) {
        function getPixelValue(value) {
            var PIXEL = /^\d+(px)?$/i;

            if (PIXEL.test(value)) {
                return parseInt(value,base);
            }

            var 
                style = el.style.left,
                runtimeStyle = el.runtimeStyle.left;

            el.runtimeStyle.left = el.currentStyle.left;
            el.style.left = value || 0;
            value = el.style.pixelLeft;
            el.style.left = style;
            el.runtimeStyle.left = runtimeStyle;

            return value;
        }

        var 
            el = document.body,
            retVal = 0;

        if (document.defaultView && document.defaultView.getComputedStyle) {
            retVal =  document.defaultView.getComputedStyle(el, null)[prop];
        } else {//IE8 & below
            retVal =  getPixelValue(el.currentStyle[prop]);
        } 

        return parseInt(retVal,10);
    }

    return document.body.offsetHeight +
        getComputedBodyStyle('marginTop') +
        getComputedBodyStyle('marginBottom');
}
David Bradshaw
  • 11,859
  • 3
  • 41
  • 70
  • This doesnt work with items that "roll up" e.g datatables or floating div's. The height is based on whatever the normal unrolled-up height would be and not the final height. – djack109 Oct 12 '16 at 04:06
  • @djack109 most likely something in your CSS stops an element shrinking on your page – David Bradshaw Oct 13 '16 at 04:50
4

Other answers were not working for me so i did some changes. Hope this will help

$('#iframe').on("load", function() {
    var iframe = $(window.top.document).find("#iframe");
    iframe.height(iframe[0].ownerDocument.body.scrollHeight+'px' );
});
Ravi
  • 163
  • 2
  • 11
3

Just in case this helps anyone. I was pulling my hair out trying to get this to work, then I noticed that the iframe had a class entry with height:100%. When I removed this, everything worked as expected. So, please check for any css conflicts.

2

Rather than using javscript/jquery the easiest way I found is:

<iframe style="min-height:98vh" src="http://yourdomain.com" width="100%"></iframe>

Here 1vh = 1% of Browser window height. So the theoretical value of height to be set is 100vh but practically 98vh did the magic.

Binod
  • 85
  • 3
2

I am using jQuery and the code below working for me,

var iframe = $(window.top.document).find("#iframe_id_here");
iframe.height(iframe.contents().height()+'px' );
sree
  • 3,113
  • 2
  • 18
  • 13
2

in my project there is one requirement that we have make dynamic screen like Alignment of Dashboard while loading, it should display on an entire page and should get adjust dynamically, if user is maximizing or resizing the browser’s window. For this I have created url and used iframe to open one of the dynamic report which is written in cognos BI.In jsp we have to embed BI report. I have used iframe to embed this report in jsp. following code is working in my case.

<iframe src= ${cognosUrl} onload="this.style.height=(this.contentDocument.body.scrollHeight+30) +'px';" scrolling="no" style="width: 100%; min-height: 900px; border: none; overflow: hidden; height: 30px;"></iframe>
1

You can refer related question here - How to make width and height of iframe same as its parent div?

To set dynamic height -

  1. We need to communicate with cross domain iFrames and parent
  2. Then we can send scroll height/content height of iframe to parent window

And codes - https://gist.github.com/mohandere/a2e67971858ee2c3999d62e3843889a8

Community
  • 1
  • 1
Mohan Dere
  • 4,497
  • 1
  • 25
  • 21
1

All other answers are correct but what if the iframe has some dynamic content like a map that loads later and dynamically changes your iframe scroll height. This is how I achieved it.

var iFrameID = document.getElementById('idIframe');

intval =  setInterval(function(){
if(iFrameID.scrollHeight == iFrameID.contentWindow.document.body.scrollHeight){
     clearInterval(intval);
}else{
   iFrameID.height = iFrameID.contentWindow.document.body.scrollHeight + "px";
  }
},500)

I simply wrap the code inside setInterval which matches the iframe scroll height with iframe content scroll height then clear the interval.

Nisar Ahmed
  • 151
  • 1
  • 6
0

I found the answer from Troy didn't work. This is the same code reworked for ajax:

$.ajax({                                      
    url: 'data.php',    
    dataType: 'json',                             

    success: function(data)
    {
        // Put the data onto the page

        // Resize the iframe
        var iframe = $(window.top.document).find("#iframe");
        iframe.height( iframe[0].contentDocument.body.scrollHeight+'px' );
    }
});
0

To add to the chunk of window that seems to cut off at the bottom, especially when you don't have scrolling I used:

function resizeIframe(iframe) {
    var addHeight = 20; //or whatever size is being cut off
    iframe.height = iframe.contentWindow.document.body.scrollHeight + addHeight + "px";
  }
Matt Stacey
  • 109
  • 2
  • 10
0

This one is useful when you require a solution with no jquery. In that case you should try adding a container and set a padding to it in percentages

HTML example code:

<div class="iframecontainer">
    <iframe scrolling="no" src="..." class="iframeclass"width="999px" height="618px"></iframe>
</div>

CSS example code:

.iframeclass{
    position: absolute;
    top: 0;
    width: 100%;
}

.iframecontainer{
    position: relative;
    width: 100%;
    height: auto;
    padding-top: 61%;
}
Juan M
  • 1
  • 3
0

The simple solution is to measure the width and height of the content area, and then use those measurements to calculate the bottom padding percentage.

In this case, the measurements are 1680 x 720 px, so the padding on the bottom is 720 / 1680 = 0.43 * 100, which comes out to 43%.

.canvas-container {    
    position: relative;
    padding-bottom: 43%; // (720 ÷ 1680 = 0.4286 = 43%)
    height: 0;
    overflow: hidden;   
}

.canvas-container iframe {    
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;   
}
Tot Zam
  • 8,406
  • 10
  • 51
  • 76
loek
  • 1
0

A slightly improved answer to BlueFish...

function resizeIframe(iframe) {
    var padding = 50;
    if (iframe.contentWindow.document.body.scrollHeight < (window.innerHeight - padding))
        iframe.height = iframe.contentWindow.document.body.scrollHeight + "px";
    else
        iframe.height = (window.innerHeight - padding) + "px";
}

This takes in consideration the height of the windows screen(browser, phone) which is good for responsive design and iframes that have huge height. Padding represents the padding you want above and below the iframe in the case it goes trough whole screen.

Tadej Vengust
  • 1,351
  • 4
  • 18
  • 35
0
jQuery('.home_vidio_img1 img').click(function(){
    video = '<iframe src="'+ jQuery(this).attr('data-video') +'"></iframe>';
    jQuery(this).replaceWith(video);
});

jQuery('.home_vidio_img2 img').click(function(){
    video = <iframe src="'+ jQuery(this).attr('data-video') +'"></iframe>;
    jQuery('.home_vidio_img1 img').replaceWith(video);
    jQuery('.home_vidio_img1 iframe').replaceWith(video);
});

jQuery('.home_vidio_img3 img').click(function(){
    video = '<iframe src="'+ jQuery(this).attr('data-video') +'"></iframe>';
    jQuery('.home_vidio_img1 img').replaceWith(video);
    jQuery('.home_vidio_img1 iframe').replaceWith(video);
});

jQuery('.home_vidio_img4 img').click(function(){
    video = '<iframe src="'+ jQuery(this).attr('data-video') +'"></iframe>';
    jQuery('.home_vidio_img1 img').replaceWith(video);
    jQuery('.home_vidio_img1 iframe').replaceWith(video);
});
Pang
  • 9,564
  • 146
  • 81
  • 122
0

Sample using PHP htmlspecialchars() + check if height exists and is > 0:

$my_html_markup = ''; // Insert here HTML markup with CSS, JS... '<html><head></head><body>...</body></html>'
$iframe = '<iframe onload="if(this.contentWindow.document.body.scrollHeight) {this.height = this.contentWindow.document.body.scrollHeight;}" width="100%" src="javascript: \''. htmlspecialchars($my_html_markup) . '\'"></iframe>';
jteks
  • 603
  • 7
  • 15
0

Script

<script type="text/javascript" language="javascript">
    $(document).ready(function(){
        var height = $(window).height();
        $('.myIframe').css('height', height - 200);
    });
</script>

iframe

<iframe class="myIframe" width="100%"></iframe>

It's working in my case.

Riaz Mahmud
  • 119
  • 1
  • 4
  • 6
0

Although I'm sure iframe-resizer is a wonderful library, I didn't want to add a 13kb dependency on the parent window and another 13kb dependency within the iFrame contents.

Here's the slim, simple, and cross-domain solution I implemented instead:

Parent window:

window.addEventListener("message", (event) => {
    if (event.data.type === "resize") {
        const iframe = document.querySelector("iframe");
        iframe.height = event.data.value + "px";
    }
}, false);

Child iframe window:

window.addEventListener("load", (event) => {
    const el = document.querySelector("html");

    const styles = window.getComputedStyle(el);
    const margin = parseFloat(styles['marginTop']) + parseFloat(styles['marginBottom']);

    const height = Math.ceil(el.offsetHeight + margin);

    window.parent.postMessage({
        type: "resize",
        value: height
    }, "*");
});
Jeremy
  • 342
  • 2
  • 9
-1
$(document).height() // - $('body').offset().top

and / or

$(window).height()

See Stack Overflow question How to get the height of a body element.

Try this to find the height of the body in jQuery:

if $("body").height()

It doesn't have a value if Firebug. Perhaps that's the problem.

Community
  • 1
  • 1
Michael L Watson
  • 964
  • 13
  • 23
  • I tried doing both ...it still happens on Firefox. firefox somehow does not get the window.height() on the iframe. As I mentioned, the script is attached to the Iframe content and I am calling it in the document.ready() function – karry Feb 06 '12 at 16:42
-3

just make iframe container position:absolute and iframe will automatically change its height according to its content

<style>
   .iframe-container {
       display: block;
       position: absolute;
       /*change position as you need*/
       bottom: 0;
       left: 0;
       right: 0;
       top: 0;
   }
   iframe {
       margin: 0;
       padding: 0;
       border: 0;
       width: 100%;
       background-color: #fff;
   }
 </style>
 <div class="iframe-container">
     <iframe src="http://iframesourcepage"></iframe>
 </div>
Hatem Badawi
  • 536
  • 4
  • 9