Setting the height of a cross-domain iframe using postMessage

If you want to include information from a different domain within a web page, you might use an iframe. The trouble is that the contents of the iframe could vary in size and, because it's cross domain, the parent can't access the iframe contents to determine how big they are; the iframe is also unable to send messages to the parent.

Now that Firefox 3 (>= beta 3) supports window.postMessage(), as do the latest WebKit nightlies and Opera 9 (though Opera uses document.postMessage()), it's possible for the iframe to determine the size of its contents and send that to the parent window, which can then resize the iframe accordingly:

In the iframe (which has an element with an id of "foo" enclosing the main content):


function postSize(e){
  var target = parent.postMessage ? parent : (parent.document.postMessage ? parent.document : undefined);

  if (typeof target != "undefined" && document.body.scrollHeight)
    target.postMessage(document.getElementById("foo").scrollHeight, "*");
}
window.addEventListener("load", postSize, false);

In the parent document (which contains the iframe with an id of "bar"):


function receiveSize(e){
  if (e.origin === "http://www.example.com") // for security: set this to the domain of the iframe - use e.uri if you need more specificity
    document.getElementById("bar").style.height = e.data + "px";
}

window.addEventListener("message", receiveSize, false);
Update: added wildcard origin parameter, as postMessage changed slightly.

Comments

That's a great usage of this feature. If it wasn't an intended usecase, or even the primary usecase, I'd be surprised.

The next issue is protocols for the messages. I guess the natural approach would be to send formatted documents, e.g. soap envelopes. You'd need to get the media type in there, so RFC 2387 URIs as payload would do nicely.

Also, you could use this for messaging gateways to send asynchronous messages without polling loops. The only poller would be in the contained iframe. Hm. The poller could be checking a message box that any old document was able to POST to... Lots of possibilities.

Posted by: Lucas on February 22, 2008 3:51 AM

Just tested in Opera 9.26 and your code had issues when testing with cross-domain iframes. Opera raise an exception when trying to access parent.postMessage.

You better test Opera first :

var target = parent.document.postMessage ? parent.document : (parent.postMessage ? parent : undefined);

And it raise the same exception in Firefox3 now ;-)

So, we have to try/catch or not use object detection at all.

All fields are optional, email address will not be shown; no HTML, URLs are automatically hyperlinked.