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.
- Previous post: Visited links can only be differentiated by colour
- Next post: Using max-width on images can make them disappear in IE8