Iframe loading techniques and performance

Iframe setTimeout() does not work in IE9
Chad Barnsdale of Unfinishedman.com mentioned to me on May 25 that the Iframe setTimeout() technique does not work in IE9. And he was right. The file that gets loaded into the iframe simply does not load. Nothing happens. I will dive into this sometime soon. It's probably something small with the JavaScript code.

Iframes are often used to load third party content, ads and widgets. The main reason to use the iframe technique is that the iframe content can load in parallel with the main page: it doesn't block the main page. Loading content in an iframe does however have two downsides, as Steve Souders outlines in his blog post Using Iframes Sparignly:

The onload blocking is the biggest problem of the two and hurts performance the most. You really want the load event to fire as soon as possible, for optimal user experience of course but also because of how Google measures your site speed: Google Toolbar in IE and FF browsers of site visitors measures time to onload.

How can you load an iframe without blocking onload and as a result improve page performance?

This article shows 4 ways to load an iframe in a web page: Normal Iframe, Iframe After Onload, Iframe setTimeout() and Dynamic Asynch Iframe. For each the behaviour related to the load event is described and shown by way of IE8 waterfall charts. I recommend to look closely at the Dynamic Asynch Iframe technique because this one is great for performance. Oh, and as a bonus, I throw in the Friendly Iframe technique. It doesn't really qualify as an iframe loading technique, but it has to do with iframes, ads and (non)-blocking.

Normal Iframe

You all know this one. It's the default way to load an iframe and works in all browsers:

<iframe src="/path/to/file" frameborder="0" width="728" height="90" scrolling="auto">
</iframe>

Using the Normal Iframe technique will result in the following behaviour in all browsers:

I created a simple test page and ran it through Webpagetest.org (IE7 and IE8). The waterfall chart below clearly shows how the Normal Iframe blocks the main page onload.
Normal Iframe - Performance - IE8 waterfall chart
Click for bigger version. View full test results on Webpagetest.org

My advice: be aware of the onload blocking. It's not a big problem if the iframe content takes a short time to load (and execute), and the iframe in itself is good to use because it loads in parallel with the main page. But if it takes long for the iframe to finish, the user experience is damaged. Test it on your page(s) and run it through Webpagetest.org a few times, look at the impact on onload (Doc Complete time) and decide if you need a better technique.

Iframe After Onload

Imagine you want to load something in an iframe, but it's not really important for the page. Or the content of the iframe is not immediately visible to the user because it's way down below the fold or hidden behind a link/tab. Consider deferring the loading of the iframe until after the main page is done.

<script>
//doesn't block the load event
function createIframe(){
  var i = document.createElement("iframe");
  i.src = "path/to/file";
  i.scrolling = "auto";
  i.frameborder = "0";
  i.width = "200px";
  i.height = "100px";
  document.getElementById("div-that-holds-the-iframe").appendChild(i);
};
	
// Check for browser support of event handling capability
if (window.addEventListener)
window.addEventListener("load", createIframe, false);
else if (window.attachEvent)
window.attachEvent("onload", createIframe);
else window.onload = createIframe;

</script>

The Iframe After Onload technique will consistently show the following behaviour in all browsers:

I ran some tests with my Iframe After Onload test page on Webpagetest.org (IE7 and IE8): as expected, onload is not blocked:
Iframe After Onload - Performance - IE8 waterfall chart
Click for bigger version. View full test results on Webpagetest.org

What do you gain by this versus the Normal Iframe? The load event of the main page fires sooner, and this has 2 benefits: Unfortunately, your site visitors will still see browser busy indicator(s) while the iframe is loading and that means that they will see those indicators for a longer period of time (versus Normal Iframe). Another downside of loading the iframe after onload is that there is a bigger chance the user leaves the page before the iframe has finished loading. In some cases this may be a real problem, e.g. you have a deal with a ad/widget provider that is based on # impressions.

Iframe setTimeout()

The objective is to load the iframe without blocking onload.
Steve Souders (him again) published a demo page for this 'trick' some time ago. He writes:
"the SRC is set dynamically in a function called via setTimeout. This technique avoids the blocking behavior of iframes in all browsers".
And that is not 100% true. I did several tests with his demo page in many browsers and found out that in IE8 - but not in IE7 (!?) - the main page onload *is* blocked on first visit (empty cache), but not on subsequent visits (primed cache). I saw the same results on my own little test page. Conclusion: this technique will often not have the desired effect in IE8, a popular browser. Too bad!

<iframe id="iframe1" src="" width="200" height="100" border="2"></iframe>
<script>
function setIframeSrc() {
  var s = "path/to/file";
  var iframe1 = document.getElementById('iframe1');
  if ( -1 == navigator.userAgent.indexOf("MSIE") ) {
    iframe1.src = s;
  }
  else {
    iframe1.location = s;
  }
}
setTimeout(setIframeSrc, 5);
</script>

In all browsers but IE8, the Iframe setTimeout() technique will consistently show the following behaviour:

I ran tests on Webpagetest.org (IE7 and IE8) with Iframe After Onload test page A and Iframe After Onload test page B: all is fine in IE7, onload is blocked on first view in IE8.
Iframe setTimeout - Performance - IE8 waterfall chart
IE8 first view. Click for bigger version. View full test results on Webpagetest.org

Iframe setTimeout - Performance - IE8 Repeat View waterfall chart
IE8 repeat view (note: my HTML is cached for 10 minutes, so only iframe content is reloaded). Click for bigger version. View full test results on Webpagetest.org

Because of the IE8 issue I believe this technique is not usable in production for many sites. If more than 10% of your visitors have IE8, 1 in 10 will get a lesser experience. You could argue that it's only worse compared to the Normal Iframe technique which isn't a really bad for performance anyway. And onload firing later for 10% of your users ... ah well. You decide, but not after you read below about the ultra awesome Dynamic Asynch Iframe-technique.

Dynamic Asynch Iframe

When I was at the Velocity 2010 web performance conference, two Meebo engineers (@marcuswestin and Martin Hunt) gave a presentation about the new Meebo Bar and how they improved this widget's performance. They came up with a truly non-blocking, instantly loading technique for including their widget in a page, using an iframe. For many web developers, their 'dynamic asynch iframe' approach was new. And it's awesome. Double awesome. For some reason, this technique has not gotten the attention it deserves. I hope this blog post can help spread the word.

<script>
(function(d){
  var iframe = d.body.appendChild(d.createElement('iframe')),
  doc = iframe.contentWindow.document;

  // style the iframe with some CSS
  iframe.style.cssText = "position:absolute;width:200px;height:100px;left:0px;";
  
  doc.open().write('<body onload="' + 
  'var d = document;d.getElementsByTagName(\'head\')[0].' + 
  'appendChild(d.createElement(\'script\')).src' + 
  '=\'\/path\/to\/file\'">');
  
  doc.close(); //iframe onload event happens

  })(document);
</script>

The magic is in the <body onload="">: the iframe has no content initially, so onload of the iframe fires instantly. Then, you create a new script element, set its source to the JS file that loads the content/ad/widget, append the script to the HEAD and voila: the iframe content loads without blocking the main page onload! You should see the following behaviour of the Dynamic Asynch Iframe technique consistently in all browsers:

My Dynamic Asynch Iframe test page gave this result on Webpagetest.org (IE8):
Iframe Dynamic Asynch - Performance - IE8 waterfall chart
Click for bigger version. View full test results on Webpagetest.org

Espacing characters makes it more difficult to read and error prone, but in my opinion these are minor cons. Do give this technique a try and post a comment if it works, or doesn't.

Friendly Iframe

This technique is for ads. It's not really an iframe loading technique, but more of a way to use an iframe to hold ads. The magic is not in how the iframe is loaded, but in how the main page, the iframe and ad codes work together. It works like this:

The Friendly Iframe works in all browsers.
The Ad Ops Council of the IAB has been recommending this technique since October 2008 as per their Best Practices for Rich Media Ads in Asynchronous Ad Environments (PDF). AOL uses this technique and Dave Artz of AOL describes it in his Velocity 2009 presentation: download PDF. Wanna see code? Dave has a Friendly Iframe test page on his blog. Aftonbladet - a large publisher in Sweden - had good results with the Friendly Iframe: on their Homepage, load time went down by 30%, visits/week went up by 7% and click-throughs to the Latest News section increased by 35%! I recommend watching the Aftonbladet presentation High Performance Web Sites, With Ads: Don't let third parties make you slow

I've not created a test page for the Friendly Iframe, so I don't have any hands-on experience with it. From what I've read so far, and by reviewing and using Dave Artz' test page, this is my view on the Friendly Iframe:

Your feedback please!

I'm looking forward to receiving your questions and remarks.
Does a technique exist that I haven't mentioned? Am I wrong about something? Speak up!
Leave your comment below (now comment), send me a message via Twitter or via email: aaron {at} aaronpeters {dot} nl.

Like it? Share it!

Iframe Performance Links

Comments