Modern browsers have some new features that make this task easier than it use to be.
PostMessage
The postMessage API provides a simple method for comunicating between an iFrame and its parent.
To send a message to the parent page you call it as follows.
parent.postMessage('Hello parent','http://origin-domain.com');
In the other direction we can send the message to the iFrame with the following code.
var iframe = document.querySelector('iframe');
iframe.contentWindow.postMessage('Hello my child', 'http://remote-domain.com:8080');
To recevie a message create an event listerner for the message event.
function receiveMessage(event)
{
if (event.origin !== "http://remote-domain.com:8080")
return;
console.log(event.data);
}
if ('addEventListener' in window){
window.addEventListener('message', receiveMessage, false);
} else if ('attachEvent' in window){ //IE
window.attachEvent('onmessage', receiveMessage);
These examples uses the origin property to limit where the message is sent to and to check where it came from. It is possible to specify *
to allow sending to any domain and you may in some cases you may want to accept messages from any domain. However, if you do this you need to consider the security implications and implement your own checks on the incoming message to ensure it contains what your expecting. In this case the iframe can post its height to '*', as we might have more than one parent domain. However, it's a good idea to check incoming messages are from the iFrame.
function isMessageFromIFrame(event,iframe){
var
origin = event.origin,
src = iframe.src;
if ((''+origin !== 'null') && (origin !== src.substr(0,origin.length))) {
throw new Error(
'Unexpect message received from: ' + origin +
' for ' + iframe.id + '. Message was: ' + event.data
);
}
return true;
}
MutationObserver
The other advance in more modern broswers is MutationObserver which allows you to watch for changes in the DOM; so it is now possible to detect changes that could affect the size of the iFrame without having to constantly poll with setInterval.
function createMutationObserver(){
var
target = document.querySelector('body'),
config = {
attributes : true,
attributeOldValue : false,
characterData : true,
characterDataOldValue : false,
childList : true,
subtree : true
},
observer = new MutationObserver(function(mutations) {
parent.postMessage('[iframeResize]'+document.body.offsetHeight,'*');
});
log('Setup MutationObserver');
observer.observe(target, config);
}
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
if (MutationObserver){
createMutationObserver();
}
Working out an accurate height
Getting an accurate height for the iFrame is not as simple as it should be, as you have a choice of six different properties that you can check and none of them give a constantly right answer. The best solution I've come up with is this function that works so long as you don't use CSS to overflow the body tag.
function getIFrameHeight(){
function getComputedBodyStyle(prop) {
const style = document.defaultView.getComputedStyle(
document.body, null);
return parseInt(style.getPropertyValue(prop), 10);
}
return document.body.offsetHeight +
getComputedBodyStyle('marginTop') +
getComputedBodyStyle('marginBottom');
}
This is the IE9 version, for the much long IE8 version see this answer.
If you do overflow the body and you can't fix your code to stop this, then using either the offsetHeight
or scrollHeight
properties of document.documentElement
are your best options. Both have pros and cons and it is best just to test both and see which works for you.
Other issues
Other things to consider include: having more than one iFrame on the page, CSS :Checkbox and :Hover events causing page resize, avoiding the use of height auto in the iFrames' body and html tags, and lastly the window being resized.
IFrame Resizer Library
I've wrapped all this up in a simple dependancy free library, that also provides some extra functions and page size detection algorithms not discussed here.
https://github.com/davidjbradshaw/iframe-resizer
This works in all modern browsers.
jsonp
to tarnsfer data – Pogue