93

I have a Help page, help.php that I am loading inside an iframe in main.php How can I get the height of this page once it has loaded in the iframe?

I am asking this because I can't style the height of to iframe to 100% or auto. That's why I think I need to use javascript.. I am using jQuery

CSS:

body {
    margin: 0;
    padding: 0;
}
.container {
    width: 900px;
    height: 100%;
    margin: 0 auto;
    background: silver;
}
.help-div {
    display: none;
    width: 850px;
    height: 100%;
    position: absolute;
    top: 100px;
    background: orange;
}
#help-frame {
    width: 100%;
    height: auto;
    margin:0;
    padding:0;
}

JS:

$(document).ready(function () {
    $("a.open-help").click(function () {
        $(".help-div").show();
        return false;
    })
})

HTML:

<div class='container'>
    <!-- -->
    <div class='help-div'>
        <p>This is a div with an iframe loading the help page</p>
        <iframe id="help-frame" src="../help.php" width="100%" height="100%" frameborder="1"></iframe>
    </div>  <a class="open-help" href="#">open Help in iFrame</a>

    <p>hello world</p>
    <p>hello world</p>
    <p>hello world</p>
    <p>hello world</p>
    <p>hello world</p>
</div>
karthikr
  • 97,368
  • 26
  • 197
  • 188
FFish
  • 10,964
  • 34
  • 95
  • 136

11 Answers11

108

ok I finally found a good solution:

$('iframe').load(function() {
    this.style.height =
    this.contentWindow.document.body.offsetHeight + 'px';
});

Because some browsers (older Safari and Opera) report onload completed before CSS renders you need to set a micro Timeout and blank out and reassign the iframe's src.

$('iframe').load(function() {
    setTimeout(iResize, 50);
    // Safari and Opera need a kick-start.
    var iSource = document.getElementById('your-iframe-id').src;
    document.getElementById('your-iframe-id').src = '';
    document.getElementById('your-iframe-id').src = iSource;
});
function iResize() {
    document.getElementById('your-iframe-id').style.height = 
    document.getElementById('your-iframe-id').contentWindow.document.body.offsetHeight + 'px';
}
FFish
  • 10,964
  • 34
  • 95
  • 136
  • this solution works great as the above just gets the size from the iframes cocntent within the container while this gets the `real` size – rickyduck Nov 17 '11 at 12:02
  • 2
    I believe the load event triggers on the same event loop so a setTimout of 1 millisecond will work just as well – George Mauer Jan 11 '13 at 15:31
  • hhmmm Anyone know how to get the height of an iframe that's hidden at the time of loading the parent. This method brings back 0. – JT... Mar 01 '13 at 08:07
  • 1
    You may want the `document` height, not the `body` height. Using jQuery you can grab it with `$(this.contentWindow.document).height()`. – vpiTriumph Oct 31 '13 at 19:18
  • To older ie, iframe.contentDocument.body.offsetHeight will work. http://stackoverflow.com/questions/2684693/iframe-document-body-scrollheight-is-double-the-correct-value – user1087079 Apr 26 '16 at 08:27
  • I preferr scrollHeight instead of offsetHeight see [this SO](https://stackoverflow.com/q/22675126/234110) for details – Anand Rockzz Jan 07 '18 at 23:08
  • In my tests (both in Firefox and Chrome) the 3 lines about Opera & Safari needing a kick-start cause the $('iframe').load() to be triggered again, which executes the 3 lines about Opera and Safari again, which triggers the load(), etc, resulting in an infinite loop. Since it's a rather old answer, I'm not sure those 3 lines are still necessary today. – s427 Aug 22 '18 at 10:44
  • 3
    When I run this I'm getting `Uncaught DOMException: Permission denied to access property "document" on cross-origin object` – Brady Dowling Jul 22 '21 at 14:54
53

The less complicated answer is to use .contents() to get at the iframe. Interestingly, though, it returns a different value from what I get using the code in my original answer, due to the padding on the body, I believe.

$('iframe').contents().height() + 'is the height'

This is how I've done it for cross-domain communication, so I'm afraid it's maybe unnecessarily complicated. First, I would put jQuery inside the iFrame's document; this will consume more memory, but it shouldn't increase load time as the script only needs to be loaded once.

Use the iFrame's jQuery to measure the height of your iframe's body as early as possible (onDOMReady) and then set the URL hash to that height. And in the parent document, add an onload event to the iFrame tag that will look at the location of the iframe and extract the value you need. Because onDOMReady will always occur before the document's load event, you can be fairly certain the value will get communicated correctly without a race condition complicating things.

In other words:

...in Help.php:

var getDocumentHeight = function() {
    if (location.hash === '') { // EDIT: this should prevent the retriggering of onDOMReady
        location.hash = $('body').height(); 
        // at this point the document address will be something like help.php#1552
    }
};
$(getDocumentHeight);

...and in the parent document:

var getIFrameHeight = function() {
    var iFrame = $('iframe')[0]; // this will return the DOM element
    var strHash = iFrame.contentDocument.location.hash;
    alert(strHash); // will return something like '#1552'
};
$('iframe').bind('load', getIFrameHeight );
Andrew
  • 14,204
  • 15
  • 60
  • 104
  • Hi Andrew so far very good help here. contents() works great, but I still need to test it with a bandwidth throttler. Maybe you can use the innerHeight() property. I have a problem in FF (OSX) using your solution putting the height in the hash. FF seems to keep on loading the getDocumentHeight() function in an infinitive loop? Safari is fine.. – FFish Oct 02 '10 at 20:54
  • Interesting. I've added a check that prevents the setting of the hash if there's already a value there. You may need to tweak this if you are loading Help.php with a hash value (e.g. ``) – Andrew Oct 03 '10 at 01:46
  • By the way, Assuming you can adjust for the difference in height, you probably needn't use the hash to communicate out of the iframe. If you do use the hash method, putting a `sleep(5)` in your Help.php should also be a good way of testing for any race conditions. If the iframe does somehow fire `onLoad` before `onDOMReady`, it should show up here. – Andrew Oct 03 '10 at 01:58
26

I found the following to work on Chrome, Firefox and IE11:

$('iframe').load(function () {
    $('iframe').height($('iframe').contents().height());
});

When the Iframes content is done loading the event will fire and it will set the IFrames height to that of its content. This will only work for pages within the same domain as that of the IFrame.

Jack Zach Tibbles
  • 800
  • 1
  • 11
  • 27
  • works ok but for the width i have to do it like this or the contents gets cut $('iframe').width($('iframe').contents().width()+30); – Geomorillo Dec 09 '14 at 19:59
  • @AminGhaderi Works fine for me in firefox 40.0.3 – mixkat Sep 09 '15 at 18:25
  • @mixkat i do load a website in iframe via this solution and all solution in this topic but for me not work! i think this solutions do work for one page and do not work when we load complete a website into the iframe. my english is very bad , I hope you will understand. – Amin Ghaderi Sep 09 '15 at 20:18
  • @AminGhaderi if I got this right you re expecting this to work for every page in your site but of course this won't work for all pages as it only runs once when you load the frame. So it'll work for the first page fine but then if you want it to work for longer pages you will have to do it again either by loading the frame again with the new page or by calling the contents.height at some other point in your flow – mixkat Sep 10 '15 at 21:37
10

The code to do this without jQuery is trivial nowadays:

const frame = document.querySelector('iframe')
function syncHeight() {
  this.style.height = `${this.contentWindow.document.body.offsetHeight}px`
}
frame.addEventListener('load', syncHeight)

To unhook the event:

frame.removeEventListener('load', syncHeight)
cchamberlain
  • 17,444
  • 7
  • 59
  • 72
6

You don't need jquery inside the iframe to do this, but I use it cause the code is so much simpler...

Put this in the document inside your iframe.

$(document).ready(function() {
  parent.set_size(this.body.offsetHeight + 5 + "px");  
});

added five above to eliminate scrollbar on small windows, it's never perfect on size.

And this inside your parent document.

function set_size(ht)
{
$("#iframeId").css('height',ht);
}
RkaneKnight
  • 95
  • 1
  • 2
5

simple one-liner starts with a default min-height and increases to contents size.

<iframe src="http://url.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>
Pixelomo
  • 6,373
  • 4
  • 47
  • 57
4

this is the correct answer that worked for me

$(document).ready(function () {
        function resizeIframe() {
            if ($('iframe').contents().find('html').height() > 100) {
                $('iframe').height(($('iframe').contents().find('html').height()) + 'px')
            } else {
                setTimeout(function (e) {
                    resizeIframe();
                }, 50);
            }
        }
        resizeIframe();
    });
Javier Gordo
  • 59
  • 1
  • 2
4

Accepted answer's $('iframe').load will now produce a.indexOf is not a function error. Can be updated to:

$('iframe').on('load', function() {
  // ...
});

Few others similar to .load deprecated since jQuery 1.8: "Uncaught TypeError: a.indexOf is not a function" error when opening new foundation project

Ryan J. Stout
  • 178
  • 1
  • 9
2

This is my ES6 friendly no-jquery take

document.querySelector('iframe').addEventListener('load', function() {
    const iframeBody = this.contentWindow.document.body;
    const height = Math.max(iframeBody.scrollHeight, iframeBody.offsetHeight);
    this.style.height = `${height}px`;
});
1

This's a jQuery free solution that can work with SPA inside the iframe

document.getElementById('iframe-id').addEventListener('load', function () {
  let that = this;
  setTimeout(function () {
    that.style.height = that.contentWindow.document.body.offsetHeight + 'px';
  }, 2000) // if you're having SPA framework (angularjs for example) inside the iframe, some delay is needed for the content to populate
});
Envil
  • 2,687
  • 1
  • 30
  • 42
0

Here is my solution, using pure JS for finding the total height of iframe content. NOTE:

  1. Call this function after the iframe is loaded.

  2. The iframe content must be in the same domain as the host page.

     function getIframeBodyTotalHeight() {
     var frm = document.getElementById("appframe");
     var frm_body = frm.contentWindow.document.body;
    
     var body_height = parseInt(frm_body.offsetHeight);
     var body_margin_top = parseInt(window.getComputedStyle(frm_body).getPropertyValue('margin-top').replace("px",""));
     var body_margin_bottom = parseInt(window.getComputedStyle(frm_body).getPropertyValue('margin-bottom').replace("px",""));
     var body_padding_top = parseInt(window.getComputedStyle(frm_body).getPropertyValue('padding-top').replace("px", ""));
     var body_padding_bottom = parseInt(window.getComputedStyle(frm_body).getPropertyValue('padding-bottom').replace("px", ""));
    
     var result = body_height + body_margin_top + body_margin_bottom + body_padding_top + body_padding_bottom;
     return result;
    }
    
Jonathan Applebaum
  • 5,738
  • 4
  • 33
  • 52