640

For example:

<iframe name="Stack" src="http://stackoverflow.com/" width="740"
        frameborder="0" scrolling="no" id="iframe"> ...
</iframe>

I want it to be able to adjust its height according to the contents inside it, without using scroll.

David Bradshaw
  • 11,859
  • 3
  • 41
  • 70
akashbc
  • 6,415
  • 3
  • 14
  • 4
  • 2
    This can be done via CSS there is a concept in css called media queries where content is resized according to the screen size – Vivek Khandelwal Apr 02 '16 at 07:20
  • 1
    Angular iFrame Auto-Height: https://gitlab.com/reduardo7/angular-iframe-auto-height – Eduardo Cuomo Oct 03 '16 at 14:51
  • 5
    "Angular…" i.e., Javascript required? In other words, one cannot do this on cross-site iframes (due to cross-site scripting restrictions), is that right? As @clankill3r is suggesting, this demonstrates the need for a pure CSS solution to this problem! – Matthew Slyman Jan 05 '17 at 20:38

16 Answers16

802

Add this to your <head> section:

<script>
  function resizeIframe(obj) {
    obj.style.height = obj.contentWindow.document.documentElement.scrollHeight + 'px';
  }
</script>

And change your iframe to this:

<iframe src="..." frameborder="0" scrolling="no" onload="resizeIframe(this)" />

As found on sitepoint discussion.

Trevor
  • 13,085
  • 13
  • 76
  • 99
hjpotter92
  • 78,589
  • 36
  • 144
  • 183
  • 373
    This will not work if the iframe contains content from another domain because of the [Same Origin Policy](http://en.wikipedia.org/wiki/Same_origin_policy), there is another Question on SO with some cross domain solutions http://stackoverflow.com/questions/5589756/is-there-a-cross-domain-iframe-height-auto-resizer-that-works – Jako Mar 27 '13 at 12:13
  • 25
    The solutions seems not to work if the content of the iframe has a change of height by js (e.g a slider) – shababhsiddique Oct 20 '13 at 04:59
  • 26
    should be `onload="resizeIframe(this);"` :) – rationalboss Dec 20 '13 at 12:40
  • 27
    Their are a few other issues you need to consider, content changing in the iframe, the browser being resized, the iframe not being full loaded when you first check it and cross domain. I put together a little library, because I couldn't find a solution that covered every issue. https://github.com/davidjbradshaw/iframe-resizer – David Bradshaw Mar 23 '14 at 13:17
  • 1
    it won't resize the size of iframe when we click on other links in iframe – Ajit Bhandari Aug 28 '14 at 12:50
  • it's not a complete solution, so of course it could not work sometimes. For example, iframe contain form, with JS validation, after error blocks shown scroll bar would appear. So there is need in additional resize event handler, that will fire resizeIframe function. – Rantiev Sep 12 '14 at 08:43
  • Worked great for Desktop Chrome, however didn't work for Android Chrome nor iPhone Safari. – hectorg87 Sep 16 '14 at 15:42
  • Not working in Firefox... – mario Jan 21 '15 at 21:20
  • Doesn't seem to work in ie7. – ᴍᴀᴛᴛ ʙᴀᴋᴇʀ Feb 25 '15 at 15:36
  • Works great in Chrome, as long as domains match. – HerrimanCoder Mar 26 '15 at 22:39
  • Also found this works great in Chrome, but content gets slightly clipped at the bottom in Firefox and IE. – Jimadine Jul 04 '15 at 10:43
  • 4
    Might be worth changing `scrolling` to `auto` in case the iframe's contents increase in height after being loaded. – rybo111 Nov 29 '15 at 17:03
  • Its not working properly of we put some other domain or any other link – Vivek Feb 26 '16 at 05:15
  • 1
    @Vivek Some websites have the CORS restricted. https://www.w3.org/TR/cors/ – hjpotter92 Feb 26 '16 at 05:32
  • 1
    Unfortunately this method is not 100% reliable. If the connection is slow, and the iframe is not loaded when the function fires, height will be not adjusted. This is because the load is only listens onpage elements only, not the iframe content. – marcias Mar 22 '16 at 08:55
  • maybe you can work around the cross sdomain policy with HTML5 iframe attribute sandbox – aeroson Aug 23 '16 at 08:40
  • 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
  • @hjpotter92 This is a great solution. I was looking for an iframe auto fit/resizer and this is the only thing that worked for me (with or without a div) and I have tried a lot since last night. Some more info: I'm using bootstrap 3 and many other JS/CSS solutions did not work as it wouldn't resize it properly vertically depending on the content that gets pulled in from a db. Just wanted to say thanks also, *cheers* – Funk Forty Niner Jan 17 '17 at 15:03
  • 1
    @hjpotter92 Addendum to my above comment. *(Slight bug)* There is a slight cut-off at the bottom though, where and for example having a letter that drops below the typeset line such as a "g", its tail gets cut off, just thought you/others might like to know and will see if I can't come up with a solution for this. – Funk Forty Niner Jan 17 '17 at 15:09
  • @Fred-ii- Probably adding a further `font-size` to the object height should resolve that. – hjpotter92 Jan 17 '17 at 15:15
  • @hjpotter92 Yes, either that or I saw a comment in an answer (inside the same question) [being this one](http://stackoverflow.com/questions/9975810/make-iframe-automatically-adjust-height-according-to-the-contents-without-using/9976309?noredirect=1#comment53882254_32162488) where I modified your line to read as `obj.style.height = (obj.contentWindow.document.body.scrollHeight +5) + 'px';` which worked (for me) beautifully, and I can live with that. Although, I could have probably just added an extra `
    ` under my last pulled db record in php. There's *always* a way ;-)
    – Funk Forty Niner Jan 17 '17 at 15:20
  • 1
    This will only make the iframe grow. It will never shrink. Put obj.style.height = 0 before reading the body height. – Sergey Gussak May 26 '17 at 01:32
  • Not working Chrom – Sandeep Sherpur Dec 05 '17 at 08:41
  • As you can see you get now the iframe for test1 link in height size 648px and for test2 link in height 2200px and for test3 link in height 440px and so on... you can add as many link as you want with as many sizez as you want. Only drawback with this code is that it only works for one iframe on a page, not more then one and parent codes from within the iframe do not work in any browser except explorer. But you can use _self, _top and _blank or names targets. Not _parent, that does not work. – SeekLoad Jul 03 '18 at 12:35
  • @SeekLoad Using jsfiddle.net link would've been easier =) I'll update my answer above with a snippet if you could provide me a [mcve] jsfiddle link – hjpotter92 Jul 03 '18 at 14:09
  • NOTE: I know this question is already answered, but I TESTED all the answers and none of them worked as they should, and in the way the question was asked, so I fiddled with the codes and I found an answer that works. – SeekLoad Jul 06 '18 at 13:26
  • @hjpotter92 The easiest way to do it if you ask me, is to simply make a HTML/HTM file in your computer and test the code. That is how I do it, no need for links and online emulators such. That way you know for sure how and if it works. Also advise is to test on more then one browser, so you see if it works on multiple platforms. – SeekLoad Jul 06 '18 at 13:29
  • @hjpotter92 Since the answer to this question is marked as answered, although the marked answer did not work properly, I cannot put another answer, although my answer does work properly. So the best thing I can do for you if you want an online emulator and not test it for yourself on your computer is to put it on a online emulator and give you the link. – SeekLoad Jul 06 '18 at 13:33
  • @hjpotter92 Tell me something, what good is a code if you validate it and it gets validated, but in reality it does not work to do its job on the web page? My code may not be W3 validated, but that is of NO IMPORTANCE as the important part is that it works and it does the job. If you can make it work and do the job correctly ad be validated at the same time, go ahead I am happy if that solution can be made. For now I have yet not found a validated code that works correctly yet. I would rather have a non W3 validated code that works, then a approved validated code that does not work. – SeekLoad Jul 06 '18 at 13:42
  • Here test on https://codepen.io/SeekLoad/pen/yEdQBK/ take a look, but you still need to copy it to your browser to have it working. – SeekLoad Jul 06 '18 at 15:26
  • There is another way to get this code to work cross-domain: do not use a direct link to the original (remote) iframe source. Instead, use a local script as the source, and then let the local script call the remote site, for example https://stackoverflow.com/a/36328394/888177 – Stefan May 02 '21 at 09:40
124

You can use this library, which both initially sizes your iframe correctly and also keeps it at the right size by detecting whenever the size of the iframe's content changes (either via regular checking in a setInterval or via MutationObserver) and resizing it.

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

Their is also a React version.

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

This works with both cross and same domain iframes.

David Bradshaw
  • 11,859
  • 3
  • 41
  • 70
  • 6
    This is by far the most robust solution. – brockis Mar 15 '18 at 00:41
  • 18
    note: when using for cross domain, requires you to be able to inject a js file into the iframe... Doesn't seem like a viable option when you don't control the iframe source. – Kyle Baker Mar 28 '18 at 06:00
  • A major bug in this library is that it can't handle `vh`. – Rickard Elimää Jul 15 '19 at 07:59
  • 2
    @RickardElimää would be happy to take a PR to fix `vh`. – David Bradshaw Dec 01 '19 at 18:49
  • for me it didnt worked – Michal - wereda-net May 04 '20 at 16:07
  • This would be a great solution if you can modify both the parent web-app and the web-app running within the iFrame. In my case, we launch several different web-apps within an iFrame in our web-app and most of those other web-apps are built by other teams or are legacy and the code doesn't exist anymore :( – MattWeiler May 06 '21 at 14:18
  • 1
    @MattWeiler in that case you can still just monkey patch the JS file into the other apps, you don't need to change any of their code and including that file won't have any negative effect on your old apps – David Bradshaw May 07 '21 at 09:28
  • @DavidBradshaw I'm trying to reconcile what you just wrote about monkey-patching with this comment from your project's repo: "If the other page is on a domain outside your control and you can not add JavaScript to that page, then now is the time to give up all hope of ever getting the iframe to size to the content. As it is impossible to work out the size of the contained page, without using JavaScript on both the parent and child pages." So if you don't control the external iframe domain, your library cannot work, correct? – Joel Wigton Mar 28 '22 at 16:49
  • Had to include both js files from plugin: "iframeResizer.min.js" outside iframe and "iframeResizer.contentWindow.min.js" inside iframe. Excellent. – estinamir Mar 29 '22 at 22:18
  • @JoelWigton correct, it is not possible to retrieve the size of the content in an iFrame from outside the iframe – David Bradshaw Mar 30 '22 at 08:22
89

Here is a compact version:

<iframe src="hello.html" sandbox="allow-same-origin"
        onload="this.style.height=(this.contentWindow.document.body.scrollHeight+20)+'px';">
</iframe>
Chong Lip Phang
  • 8,755
  • 5
  • 65
  • 100
51

The suggestion by hjpotter92 does not work in safari! I have made a small adjustment to the script so it now works in Safari as well.

Only change made is resetting height to 0 on every load in order to enable some browsers to decrease height.

Add this to <head> tag:

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

And add the following onload attribute to your iframe, like so

<iframe onload='resizeIframe(this)'></iframe>
rybo111
  • 12,240
  • 4
  • 61
  • 70
Allan P
  • 527
  • 4
  • 2
  • This also does not work if the iframe contents come from srcdoc attribute. The height will be set wrong. – Myforwik Jul 14 '14 at 01:04
  • Setting height to zero first is not only for IE. – aceofspades Sep 06 '14 at 16:46
  • 2
    Thanks, this probably should have been a comment/suggestion to hjpotter's post mind... – ᴍᴀᴛᴛ ʙᴀᴋᴇʀ Feb 25 '15 at 15:38
  • 4
    You don't need those encapsulating `{}`'s – Steven Vachon Mar 09 '15 at 21:30
  • 6
    `obj.style.height = 0;` is very important row, that cause scrollHeight recalculating (otherwise, your contentWindow height will only increase). – Maxim Zhukov May 17 '16 at 16:16
  • I tried calling this in `window.resize` and it keeps scrolling to the top because of the `= 0` line. Why exactly do I need this line for Safari browser? Is there any way to do this without setting the height to `0`? – ADTC Mar 11 '17 at 14:45
  • Re. my last comment: I find that using `clientHeight` works better, but you need to set `scrolling="no"` attribute in the `iframe` tag. And you may also need to add some pixels to give some extra margin (this depends on your content). Summary: Remove the `= 0` line. Use only: `obj.style.height = (obj.contentWindow.document.body.clientHeight + 50) + 'px';` (I'm adding 50px additional margin for example). Then: ``. **Bonus point:** `clientHeight` has far better browser support! – ADTC Mar 11 '17 at 16:02
15

Avoid inline JavaScript; you can use a class:

<iframe src="..." frameborder="0" scrolling="auto" class="iframe-full-height"></iframe>

And reference it with jQuery:

$('.iframe-full-height').on('load', function(){
    this.style.height=this.contentDocument.body.scrollHeight +'px';
});
rybo111
  • 12,240
  • 4
  • 61
  • 70
14

The hjpotter92 answer works well enough in certain cases, but I found the iframe content often got bottom-clipped in Firefox & IE, while fine in Chrome.

The following works well for me and fixes the clipping problem. The code was found at http://www.dyn-web.com/tutorials/iframes/height/. I have made a slight modification to take the onload attribute out of the HTML. Place the following code after the <iframe> HTML and before the closing </body> tag:

<script type="text/javascript">
function getDocHeight(doc) {
    doc = doc || document;
    // stackoverflow.com/questions/1145850/
    var body = doc.body, html = doc.documentElement;
    var height = Math.max( body.scrollHeight, body.offsetHeight, 
        html.clientHeight, html.scrollHeight, html.offsetHeight );
    return height;
}

function setIframeHeight(id) {
    var ifrm = document.getElementById(id);
    var doc = ifrm.contentDocument? ifrm.contentDocument: 
        ifrm.contentWindow.document;
    ifrm.style.visibility = 'hidden';
    ifrm.style.height = "10px"; // reset to minimal height ...
    // IE opt. for bing/msn needs a bit added or scrollbar appears
    ifrm.style.height = getDocHeight( doc ) + 4 + "px";
    ifrm.style.visibility = 'visible';
}

document.getElementById('ifrm').onload = function() { // Adjust the Id accordingly
    setIframeHeight(this.id);
}
</script>

Your iframe HTML:

<iframe id="ifrm" src="some-iframe-content.html"></iframe>

Note if you prefer to include the Javascript in the <head> of the document then you can revert to using an inline onload attribute in the iframe HTML, as in the dyn-web web page.

Jimadine
  • 998
  • 13
  • 26
7

jQuery's .contents() method method allows us to search through the immediate children of the element in the DOM tree.

jQuery:

$('iframe').height( $('iframe').contents().outerHeight() );

Remember that the body of the page inner the iframe must have its height

CSS:

body {
  height: auto;
  overflow: auto
}
Nathalia Xavier
  • 1,029
  • 10
  • 13
7

Try this:

<iframe name="Stack" src="http://stackoverflow.com/" style='height: 100%; width: 100%;' frameborder="0" scrolling="no" id="iframe">...</iframe>
András Aszódi
  • 8,948
  • 5
  • 48
  • 51
Lucky
  • 783
  • 2
  • 10
  • 28
3

This works for me (also with multiple iframes on one page):

$('iframe').load(function(){$(this).height($(this).contents().outerHeight());});
user2992220
  • 1,092
  • 1
  • 12
  • 20
2

This works for me (mostly).

Put this at the bottom of your page.

<script type="application/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js">
</script>

<script type="application/javascript" src="/script/jquery.browser.js">
</script>

<script type="application/javascript" src="/script/jquery-iframe-auto-height.js">
</script>

<script type="application/javascript"> 
  jQuery('iframe').iframeAutoHeight();
  $(window).load(
      function() {
          jQuery('iframe').iframeAutoHeight();  
      }
  );

  // for when content is not html e.g. a PDF
  function setIframeHeight() {
      $('.iframe_fullHeight').each(
          function (i, item) {
              item.height = $(document).height();
          }
      );
  };

  $(document).ready( function () {
      setIframeHeight();
  });
  $(window).resize( function () {
      setIframeHeight();
  });
</script> 

The first half is from ???, and works when there is html in the iframe. The second half sets the iframe to page height (not content height), when iframes class is iframe_fullHeight. You can use this if the content is a PDF or other such like, but you have to set the class. Also can only be used when being full height is appropriate.

Note: for some reason, when it recalculates after window resize, it gets height wrong.

ctrl-alt-delor
  • 7,506
  • 5
  • 40
  • 52
1
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"; 
}

add this to your iframe: onload="autoResize('youriframeid')"

Neil Thompson
  • 6,356
  • 2
  • 30
  • 53
Simon
  • 1,314
  • 4
  • 14
  • 26
1
jq2('#stocks_iframe').load(function(){
var iframe_width = jq2('#stocks_iframe').contents().outerHeight() ; 
jq2('#stocks_iframe').css('height',iframe_width); });

<iframe id='stocks_iframe' style='width:100%;height:0px;' frameborder='0'>
0

I did it with AngularJS. Angular doesn't have an ng-load, but a 3rd party module was made; install with bower below, or find it here: https://github.com/andrefarzat/ng-load

Get the ngLoad directive: bower install ng-load --save

Setup your iframe:

<iframe id="CreditReportFrame" src="about:blank" frameborder="0" scrolling="no" ng-load="resizeIframe($event)" seamless></iframe>

Controller resizeIframe function:

$scope.resizeIframe = function (event) {
    console.log("iframe loaded!");
    var iframe = event.target;
    iframe.style.height = iframe.contentWindow.document.body.scrollHeight + 'px';
};
Mark Amery
  • 143,130
  • 81
  • 406
  • 459
Charles Naccio
  • 328
  • 2
  • 6
0

I wanted to make an iframe behave like a normal page (I needed to make a fullscreen banner inside an iframe element), so here is my script:

    (function (window, undefined) {

    var frame,
        lastKnownFrameHeight = 0,
        maxFrameLoadedTries = 5,
        maxResizeCheckTries = 20;

    //Resize iframe on window resize
    addEvent(window, 'resize', resizeFrame);

    var iframeCheckInterval = window.setInterval(function () {
        maxFrameLoadedTries--;
        var frames = document.getElementsByTagName('iframe');
        if (maxFrameLoadedTries == 0 || frames.length) {
            clearInterval(iframeCheckInterval);
            frame = frames[0];
            addEvent(frame, 'load', resizeFrame);
            var resizeCheckInterval = setInterval(function () {
                resizeFrame();
                maxResizeCheckTries--;
                if (maxResizeCheckTries == 0) {
                    clearInterval(resizeCheckInterval);
                }
            }, 1000);
            resizeFrame();
        }
    }, 500);

    function resizeFrame() {
        if (frame) {
            var frameHeight = frame.contentWindow.document.body.scrollHeight;
            if (frameHeight !== lastKnownFrameHeight) {
                lastKnownFrameHeight = frameHeight;

                var viewportWidth = document.documentElement.clientWidth;
                if (document.compatMode && document.compatMode === 'BackCompat') {
                    viewportWidth = document.body.clientWidth;
                }

                frame.setAttribute('width', viewportWidth);
                frame.setAttribute('height', lastKnownFrameHeight);

                frame.style.width = viewportWidth + 'px';
                frame.style.height = frameHeight + 'px';
            }
        }
    }

    //--------------------------------------------------------------
    //  Cross-browser helpers
    //--------------------------------------------------------------

    function addEvent(elem, event, fn) {
        if (elem.addEventListener) {
            elem.addEventListener(event, fn, false);
        } else {
            elem.attachEvent("on" + event, function () {
                return (fn.call(elem, window.event));
            });
        }
    }

})(window);

The functions are self-explanatory and have comments to further explain their purpose.

Chris Panayotoff
  • 1,744
  • 21
  • 24
  • 1
    May be some need an explanation, at least how to use it. And what it does. (-1) – ctrl-alt-delor Jan 03 '16 at 16:02
  • This works for me on FF, but I agree with @richard that some explanation will go some way towards getting this accepted as an answer. – crafter Apr 18 '17 at 15:08
  • there is like.... 1 comment, on the obvious thing. The actual stuff i don't understand has no comments. No mention if this is affected by SOP. Worst, it uses `setTimeout` - imagine if i was on a really slow connection... – RozzA Oct 06 '17 at 04:01
-1

I've had problems in the past calling iframe.onload for dynamically created iframes, so I went with this approach for setting the iframe size:

iFrame View

var height = $("body").outerHeight();
parent.SetIFrameHeight(height);

Main View

SetIFrameHeight = function(height) {
    $("#iFrameWrapper").height(height);
}

(this is only going to work if both views are in the same domain)

Owen
  • 4,229
  • 5
  • 42
  • 50
-4
<script type="text/javascript">
  function resizeIframe(obj) {
    obj.style.height = 0;
    obj.style.height = obj.contentWindow.document.body.scrollHeight + 'px';
  }
</script>

this is not working for chrome. But working for firefox.

henrebotha
  • 1,244
  • 2
  • 14
  • 36