Emulating the HTML5 seamless iframe attribute (which browsers do not yet support)


Emulatig the seamless iframe attribute:
This page presents code for emulating seamless iframes. It sets the iframes' height to match their contents and has the iframes inherit the css of the containing document.
As far as js is concerned, the iframes will remain independent from the main document. So both the containing document and the iframed pages will have their own javascript.
To allow the reader to distinguish the iframed pages from the main document, we have given the iframed pages different text colors.

Demo:

This is some text after the seamless iframe.

Demo - explanations:
name="seamless_ifr":
We can choose any name we want. That name must be referenced in frames['...'].
for (var i = 0; i < document.getElementsByTagName('style').length; i++) {...}:
This gives the iframe the same styles as the containing document (but values for margin and padding will be overridden, see below).
this.style.height=0:
The iframe's height must be first reduced to zero in order for things to run properly.
this.style.borderWidth=0:
A seamless iframe doesn't have a border. (Of course we can give it a border 'afterwards' by wrapping it in a div having one).
this.scrolling='no':
A seamless iframe doesn't have scroll bars.
this.style.verticalAlign='top':
The iframe is an inline element. If it's not separated from the surrounding text with the help of <br> or something similar, the surrounding text will not be vertically inline with the iframe without the javascript equivalent of vertical-align: top. Not needed if we give the iframe (the js equivalent of) display: block.
frames['...'].document.body.style.padding=0; frames['...'].document.body.style.margin=0:
If we want the iframe to be seamless, it must not have margins and paddings. (Of course we can give it margins and paddings 'afterwards' by wrapping it in a div having margins and / or paddings).
this.style.height = Math.max(...):
This gives the iframe the height-minus-1px that fits its content. For cross browser compatibility, we use several methods for calculating the height. Math.max selects the highest value. Inspired by stackoverflow.com/questions/1145850.
'Minus-1px' solves a problem that may occur when the iframe is 100% wide and the iframed page contains an absolutely positioned element. In that case, some browsers will leave a blank line beneath the iframe if we don't have 'minus-1px'. As minus-1px' gives the iframe a vertical scroll bar, we put this.scrolling='no' inside the iframe tags (see above).
if(frames...location.href=='about:blank'){frames...location.href='....html'}:
To be absolutely sure that everythings works fine, we don't tell the iframe which document must be inserted until it loads. That's also why we have src="about:blank".

A function for creating seamless iframes:
Putting the onload-instructions for the iframe in a function is not very complicated (and not absolutely required either: the code explained above already does what it must do). Here it is.
Function:
<script>
function seamless_emul(which,url)
{
for (var i = 0; i < document.getElementsByTagName('style').length; i++)
{frames[which].document.getElementsByTagName('head')[0].appendChild(document.getElementsByTagName('style')[i].cloneNode(true))};
document.getElementById(which).style.height=0;
document.getElementById(which).style.borderWidth=0;
document.getElementById(which).scrolling='no';
document.getElementById(which).style.verticalAlign='top';
frames[which].document.body.style.padding=0;
frames[which].document.body.style.margin=0;
document.getElementById(which).style.height=Math.max(frames[which].document.body.scrollHeight, frames[which].document.body.offsetHeight, frames[which].document.documentElement.clientHeight, frames[which].document.documentElement.scrollHeight, frames[which].document.documentElement.offsetHeight) -1 +'px';
if(frames[which].location.href=='about:blank')
{frames[which].location.href=url};
}
</script>
Usage (name and id must be identical):
<iframe style="width: ..." src="about:blank" name="some_iframe" id="some_iframe" onload="seamless_emul('some_iframe','....html')"></iframe>
Demo:

This is some text after the seamless iframe.

Modifying the iframe's contents:
Using links like the following in the main page, we can modify the iframe's contents. The iframe will self adjust to the size of its new contents, whether or not it is created without function (like in the first demo) or with the help of a function (like in the second demo). In this third demo, the iframe has name="seamless_ifr3" id="seamless_ifr3":
<a href="javascript: void(0)" onclick="frames['seamless_ifr3'].location.replace('demo1.html')">load demo1.html in the iframe below</a> --> demo
<a href="javascript: void(0)" onclick="frames['seamless_ifr3'].location.replace('demo2.html')">load demo2.html in the iframe below</a> --> demo
<a href="javascript: void(0)" onclick="frames['seamless_ifr3'].location.replace('demo3.html')">load demo3.html in the iframe below</a> --> demo

If we want to obtain the same results using links within the iframed (external) page itself, we would use lines like the following inside the external document:
<a href="javascript: void(0)" onclick="parent.frames['seamless_ifr3'].location.replace('demo1.html')">load demo1.html in the iframe</a> or:
<a href="javascript: void(0)" onclick="location.replace('demo1.html')">load demo1.html in the iframe</a> etc.
Please try for yourself.

The effect of resizing the window:
This will cause the iframe(s) to not being seamless anymore until we refresh the main document or load another external document in the iframe(s). One way to solve this problem is to give the iframes that we want to be seamless a class name, for instance class="seamless_class" and then put the following script in the containing document:
<script>
window.onresize=function()
{
for (var i = 0; i < document.getElementsByClassName('seamless_class').length; i++)
{document.getElementsByClassName('seamless_class')[i].src = document.getElementsByClassName('seamless_class')[i].src}
}
</script>


Arie Molendijk, mesdomaines.nu.