How to adjust an iframe element’s height to fit its content

In an ideal world there would always be a clean way of displaying data supplied by a third party on your site. Two examples would be getting the data in JSON or XML format from a Web Service and having an API to code against. But you don’t always have any of those options.

Sometimes the only way of incorporating data from a third party is by loading it in an iframe element. A few examples are financial reports, e-commerce applications, and ticket booking applications. Using an iframe is not ideal for many reasons, one of which is that it can make multiple sets of scrollbars appear on the page. Not only does it look ugly, it also makes the site less user-friendly. But there is a workaround.

Adjust the iframe’s height with JavaScript

By using the following piece of JavaScript you can adjust the height of the iframe element to match the height of its content:

function setIframeHeight(iframe) {
    if (iframe) {
        var iframeWin = iframe.contentWindow || iframe.contentDocument.parentWindow;
        if (iframeWin.document.body) {
            iframe.height = iframeWin.document.documentElement.scrollHeight || iframeWin.document.body.scrollHeight;
        }
    }
};

The iframe parameter is a reference to the iframe element you want to set the height of.

To make sure that any elements that may effect the content’s height are loaded I normally attach the function to the window.onload event. You can either use your favourite JavaScript library to do that or hardcode it like this:

window.onload = function () {
    setIframeHeight(document.getElementById('your-frame-id'));
};

With jQuery the above could look like this:

$(window).load(function () {
    setIframeHeight(document.getElementById('your-frame-id'));
});

The script should work in most browsers – I’ve tested in Firefox, Safari, Opera, Chrome, and IE 6-9. See it in action on the iframe height demo page.

However, there is a slight problem in IE 8 and older. Those browsers won’t let you use CSS (border:0) to remove the border from the iframe element. To do that you will need to use the frameborder attribute. Unfortunately the frameborder attribute is invalid in HTML5, so you’ll have to live with a validation error (“The frameborder attribute on the iframe element is obsolete. Use CSS instead.”) if you use HTML5 and want the border gone in IE 8 and older.

Use CSS to set a min-height fallback

Sometimes you can have some reasonable idea of how tall the page loaded in the iframe will be. In those cases you can use CSS to give the iframe a minimum height as a fallback for users without JavaScript and in case the script fails to run:

#external-frame {min-height:800px;} /* Or whatever you’re guessing the height will be. */

Different domains

As long as the page containing the iframe element and the page that is loaded inside the iframe are on the same domain (and are using the same protocol, i.e. http or https), the script above will work. However, if, as is often the case, the page loaded inside the iframe is on another domain, there are security restrictions in JavaScript (the Same origin policy for JavaScript) that will not let the containing page access the document loaded in the iframe.

Different browsers give slightly different errors:

  • Firefox: Permission denied to access property ‘document’
  • Safari: Unsafe JavaScript attempt to access frame with URL http://example.com/ from frame with URL http://example.org/. Domains, protocols and ports must match.
  • Opera: Uncaught exception: ReferenceError: Security error: attempted to read protected variable

This problem can be worked around by using document.domain if both documents are on the same top level domain, are using the same protocol and you can add the following line of JavaScript to the page in the iframe:

document.domain = "example.com";

You’ll obviously need to replace “example.com” with your site’s domain, and the page containing the iframe needs the same line to make the domains match. Once this is in place, the script running on your main page is allowed to access properties of the document in the iframe element.

If the content in the iframe cannot be on the same top level domain or you are unable to add the document.domain line, your best bet is to use a CSS fallback to specify a guesstimated min-height. If your guess is off, users will either get a scrollbar in the iframe or extra whitespace at the bottom of it.

Avoid the iframe mess if possible

The technique described here is not bulletproof. Other than the domain problems, the height of the iframe isn’t recalculated if the user increases text size, the window is resized, or more content is loaded into the iframe. Some of those cases can be worked around, but I haven’t done so here.

While you can sometimes make iframes appear seamless to the user, it isn’t always possible. Next time you run into this problem, take the opportunity to put some pressure on third parties to make it possible to use their services without resorting to hacky iframes.

Posted on December 16, 2011 in JavaScript, Usability

Comments are disabled for this post (read why), but if you have spotted an error or have additional info that you think should be in this post, feel free to contact me.