ASP.NET - How to adjust an iframe element’s height to fit its content and populate content server-side

In a perfect developer's world you would always have an easy way of displaying data from a third party site. Examples might be getting data in JSON format from a web service and having a clean API that you can code against. Unfortunately, we don't always have this option.

Sometimes the only way of incorporating data from a third party is to load it into an iframe element. Some examples might be financial reports and stock information. Using an iframe is not ideal ; one of the reasons is that it can make multiple sets of scrollbars appear on the page. Not only does that 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 JavaScript code 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 above is a reference to the iframe element you want to set the height of.

To make sure that any DOM elements that may effect the content’s height are loaded, you would normally attach the function to the window.onload event. You can either use jQuery to do that or hardcode it like this:

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

With jQuery the above could look like this:

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

The script should work in most browsers.

However, there is a problem in IE 8 and older. Older 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 -- but the frameborder attribute is invalid in HTML5, so you’ll have to live with a validation error if you use HTML5 and you want to eliminate the border in IE 8 and older.

Use CSS to set a min-height fallback
Sometimes you can have some idea of the height of the content loaded in the iframe will be. In those cases you can use CSS to give the iframe a minimum height as a fallback:

#external-frame {min-height:800px;} /* Or whatever your best guess of the height is. */

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, the script above will work. However, if the page loaded inside the iframe is on another domain, there are security restrictions in JavaScript (Same origin policy) 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 the  document.domain property; 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 = "domainforiframecontent.com";

The page containing the iframe needs the same line of code to make the domains match. Once this is in place, the script running on your main page will be 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. For ASP.NET developers, an option is my Alternate Server-side method described below.

Avoid  iframes where possible

The technique described here is not perfect. 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.

Alternate Server-side method

By adding the runat=server attribute to your IFRAME, you can turn it into a server-side HtmlGeneric control. This allows you to set the content (innerHTML) in codebehind, and allows you to "get around" same - domain policy, since you are requesting the content server-side. We point the src property of the IFRAME to an ASPX page that goes out and gets the desired content, and writes it to the Response:

            WebClient wc = new WebClient();
            string path = Request.Url.GetLeftPart(UriPartial.Authority);
             // we get around same-domain restrictions by setting content server-side
            string content = wc.DownloadString("http://yahoo.com");
            wc.Dispose();
            Response.Write(content);
            

In the downloadable demo app, the page AlternateMethod.aspx illustrates this.

While you can sometimes make iframes appear seamless to the user, it isn’t always possible.  You can download the sample Visual Studio 2010 Solution here.

By Peter Bromberg   Popularity  (7017 Views)