Setting Iframe Height: Cross-Domain Version

Elsewhere we have described and demonstrated how you can use JavaScript to set the height of an iframe to match the height of its content. Here we show how you can use postMessage to accomplish this when the containing document and iframed document are on different domains.

Due to the constraints imposed by JavaScript's Same Origin Policy, the document containing the iframe is not able to access the document inside the iframe or any of the properties needed to determine its height. However, the document in the iframe can determine its own height onload and pass it to the containing document using postMessage. The containing document includes a message event handler to receive the height passed from the iframed document and set the height of the iframe accordingly.

JavaScript in Iframed Document

The following JavaScript is included in iframed documents in order to send their height to the containing (parent) document.

// Get height of document
function getDocHeight(doc) {
    doc = doc || document;
    // from http://stackoverflow.com/questions/1145850/get-height-of-entire-document-with-javascript
    var body = doc.body, html = doc.documentElement;
    var height = Math.max( body.scrollHeight, body.offsetHeight, 
        html.clientHeight, html.scrollHeight, html.offsetHeight );
    return height;
}

// send docHeight onload
function sendDocHeightMsg(e) {
    var ht = getDocHeight();
    parent.postMessage( JSON.stringify( {'docHeight': ht} ), '*' );
}

// assign onload handler 
if ( window.addEventListener ) {
    window.addEventListener('load', sendDocHeightMsg, false);
} else if ( window.attachEvent ) { // ie8
    window.attachEvent('onload', sendDocHeightMsg);
}

The getDocHeight function determines the height of the document. It should work in virtually all current browsers whether they are displaying pages in standards or quirks mode. The sendDocHeightMsg function is assigned to the onload event. JSON.stringify is applied to the document height, and postMessage is used to send it to the parent document.

Notice that the asterisk is used for the second argument to postMessage so that you can send the height of the document to any domain set up to receive it. You can specify a particular domain if you prefer.

JavaScript in Parent Document

The document containing the iframe includes an event handler to receive messages from iframed documents about their height as shown here:

// modified from same-domain version at www.dyn-web.com/tutorials/iframes/height/
function setIframeHeightCO(id, ht) {
    var ifrm = document.getElementById(id);
    ifrm.style.visibility = 'hidden';
    // some IE versions need a bit added or scrollbar appears
    ifrm.style.height = ht + 4 + "px";
    ifrm.style.visibility = 'visible';
}


// iframed document sends its height using postMessage
function handleDocHeightMsg(e) {
    // check origin
    if ( e.origin === 'http://www.example.com' ) {
        // parse data
        var data = JSON.parse( e.data );
        // check data object
        if ( data['docHeight'] ) {
            setIframeHeightCO( 'ifrm', data['docHeight'] );
        } else if ( data['href'] ) { 
            setIframe('ifrm', data['href'] );
        }
    }
}

// assign message handler
if ( window.addEventListener ) {
    window.addEventListener('message', handleDocHeightMsg, false);
} else if ( window.attachEvent ) { // ie8
    window.attachEvent('onmessage', handleDocHeightMsg);
}

Perhaps you noticed that when the iframed document sends its height to the parent, it sends it as an object literal with a docHeight property. The message handler checks the data object for this property. Notice that it also checks for an href property which is used for links in the iframed document.

Links to and In Iframes

You can include links to load new documents into the iframe and apply the JavaScript to these new pages to set the height of the containing iframe:

<a href="http://www.example.com/intro.html" target="ifrm">Introduction</a>

The setIframe function displayed below shows how we apply a new URL to an iframe using the location.replace method. Although ideally we might like the back and forward buttons to be effective in moving through the iframe's history, we cannot count on the set height JavaScript being applied in that case, so we use the location.replace method since it does not affect history.

// called onclick of links that target iframe
function setIframe(id, href) {
    var ifrm = document.getElementById(id);
    ifrm.style.height = '10px'; // reset to minimal height in case going from longer to shorter doc
    //ifrm.src = href; 
    window.frames[id].location.replace(href); // since back/forward doesn't trigger height adjustment 
}

// assign onclick handlers to links
document.getElementById('demoLinks').onclick = function(e) {
    e = e || window.event;
    var tgt = e.target? e.target: e.srcElement;
    setIframe(tgt.target, tgt.href)
}

If all the links to display new pages in the iframes are in one location (e.g., in demoLinks), we can use JavaScript to assign an onclick handler as shown above.

Links in Iframed Document

By default, links inside the iframed document will load new documents into the iframe. You can include target attributes to point to the parent document as described in Loading New Documents.

If a link is to load a new document into the iframe, you will likely want the new document to also incorporate the set height JavaScript. The JavaScript below shows how this is accomplished. The links need to be set up to call the JavaScript onclick rather than follow the URL:

<a href="more.html" onclick="return sendSetIframeMsg(this.href);">JavaScript</a>

The function called onclick is displayed here:

// Send message to parent to load new document in iframe
function sendSetIframeMsg(href) {
    if ( parent !== self) { // in iframe?
        parent.postMessage( JSON.stringify( {'href': href} ), '*' );
        return false;
    }
    return true; // follow link
}

First the function checks to be sure that the page is actually in an iframe, and then sends the links href to the parent document using postMessage. The parent document will adjust the height of the iframe and use location.replace as shown above to apply the new URL to the iframe. Then when the iframe loads, the set height JavaScript will be called, as long as the page includes the necessary JavaScript, which we include in a co-height.js file. The parent document requires the JavaScript included in set-height.js.

Back to top