If you Google around about this problem (at the time of this writing), you’ll find some incomplete answers and some other snippets advocating this bad practice:
<!-- NO! Bad! -->
<iframe src="..." style="visibility:hidden;" onload="this.style.visibility='visible';"></iframe>
The reason this is bad is that the CSS will hide the iframe no matter what and users with JavaScript turned off will never see that iframe. Now I’m not usually one to go to extreme lengths to cater to that crowd, but I’m all for using better solutions that do solve that issue when they are available.
The Solution
Thanks to Paul Irish and his Surefire DOM Element Insertion and Ryan Seddon and his article on inserting scoped style elements, we have this:
// Prevent variables from being global
(function () {
/*
1. Inject CSS which makes iframe invisible
*/
var div = document.createElement('div'),
ref = document.getElementsByTagName('base')[0] ||
document.getElementsByTagName('script')[0];
div.innerHTML = '­<style> iframe { visibility: hidden; } </style>';
ref.parentNode.insertBefore(div, ref);
/*
2. When window loads, remove that CSS,
making iframe visible again
*/
window.onload = function() {
div.parentNode.removeChild(div);
}
})();
Just include that on any page (in the <head>
) with the white flash problem and it will be solved. Just note that we’re using window.onload here, so if your page also uses that somewhere, combine them.
How it Works
- It inserts some CSS on the page (right away) which makes all iframes invisible. You can’t see a white flash on an iframe that’s not there!
- When the window is done loading (which means iframes are done loading too), this CSS is removed, which makes the iframes visible again
Browsers Affected
At the time of this writing, I’m able to replicate the problem in Chrome 11 and Safari 5 (so essentially a WebKit issue). Current Firefox, Opera, and IE are fine.
What About… other stuff?
You can put the allowtransparency="true"
attribute on the iframe. You can set the iframe’s background to transparent with CSS. You can make sure the background on the source document matches the background of the parent page. None of that stuff works. This works. Well… it works for users with JavaScript turned on, anyway. =)
What’s the “­” all about?
Check out Ryan Seddon’s article: http://www.thecssninja.com/javascript/noscope
It’s all about IE stripping the style tag on insertion, preventing that, and doing it with a character with no bearing on rendering.
(that was a “shy” character… whatever that means)
Why not just have a <noscript> tag with a normal iframe, and add the iframe via javascript for everyone else?
It cleared my html, it should read:
Why not just have “noscript” a tag with a normal iframe, and add the iframe via javascript for everyone else?
I’m not sure that would help. When the JS inserts the iframe, it still loads and still white flash. Except you could probably do the same trick of hiding visibility until it loads. Seems kinda un-scaleable to have to put the markup for every iframe you want to insert into the JavaScript, kinda crossin’ the ol’ streams of content and behavior.
You would still have to use javascript so I think this solution is easier and it should work without editing the page, just “paste it and go”
Hejsa!
Wonderful article!
One thing though: I’m sure you mean “You can’t see a white flash on an iframe that’s not there!”
Nice Article, but in general, the iFrame-technique is sooo old. You’ll better make clear to use other methods like dynamic content via PHP.
iFrames are here to stay for a while man. I think it’s a perfectly fine thing. YouTube videos are iframe embeds. Wufoo forms are iframe embeds. They are really great for hosted third party content where you need/want the control of those two things to be separate.
The iFrame Support from popular Webservices like YouTube, Facebook etc. does not mean that iFrames are a good way to handle external content. There are modern solutions like SOAP or CURL to handle this. (Sorry for my bad english, i’m from germany)
i have to agree with Chris. i work for a large corporation and we have a new, large SaaS product that is 100% reliant on iFrames.
So you think YouTube videos should provide their copy-and-paste embeddable video code as PHP with a CURL call?
iFrames are a perfect way to house outside content and as Chris said, with more and more large companies using them to embed there content (Youtube, Vimeo, Facebook, Twitter…) they are here to stay for a long time.
>> So you think YouTube videos should provide their copy-and-paste embeddable video code as PHP with a CURL call?
Yes, why not. Its also possible to share a JSON/XML/Whatever-Interface, which is easy callable via JavaScript.
I think that an iFrame makes it easy for people that are not in the design field or used to looking at a piece of code. For a large percentage of people its hard enough just to copy and paste. That could have been a reason for YouTube to switch to iFrame embed as it looks less complicated..
I implemented this flash prevention code on my site as soon as I saw it.
Thanks and great work Chris.
Does this also work if the iframe has been inserted with javascript?
I.E. :
thnx it was very useful.i will use this in my site
This is actually a great way of preventing unwanted flashes of styling on things like skinned dropdowns and custom scrollbars. Happy to see this method catching on and being used for iframes as well!
“Just note that we’re using window.onload here, so if your page also uses that somewhere, combine them.”
Why? I thought when you register multiple functions for an event, they stack and run in turn. Isn’t that so?
BTW, did you know you can get the content of the iframe via script? All you need is this:
getElementById('myiFrame').contentWindow
and it will return the ‘window’ object of that iframe, now you can go like this:Here’s a fiddle with two declarations of window.onload: http://jsfiddle.net/chriscoyier/gb7gt/ — you only get the second one. There may be a better way to handle that. I’m a noob at JavaScript.
For that second bit about accessing internal contents of iframe, that only works for same-domain iframes I’m pretty sure.
Chris is correct, ‘window.onload’ can only be attached to one function call. Using it twice means only the second call is fired. To do what you are suggesting Hassan, you would use an ‘init’ type function to run at ‘window.onload’ and then make multiple function calls to get the stacking behavior you’re describing.
Yeah totally, that’s why I said to watch out for that in the article and combine them. That’s the ideal way to do it, like you said, create an init function and call that, which contains anything you want to run on window.onload
the “proper” way is to use “attachEvent” for IE and “addEventListener” for everything else. That allows you to attach as many callbacks to an event as you want.
I managed to get rid of that white iframe flash with a site by simply using a background color with css for iframe element. Not suitable for image backgrounds but an option none the less on occassion
Thank you for such good and juicy article post :)
This is definitely can be helpful when I’m dealing with Flash.
ref = document.getElementsByTagName(‘base’)[0] ||
document.getElementsByTagName(‘script’)[0];
WOW!!!
What about applying a class to the HTML or body tag, then removing it on page load. I use a similar technique (without removing the class) for JS-dependent styles:
JavaScript in head
CSS in Stylesheet:
Also like.
Although the all-JS solution is easier to kinda copy-paste-done, and in the case of something like Wufoo form embeds (originally why I was messing with this), the only option.
What about when using this for a page with an iframe where every click on a menu-item loads different content in the same iframe. The page wont reload, only the iframe content. How to edit your script to prefent that kind of white flash?
Thanks, I’ve been looking for a solution to that problem for an hour! It doesn’t look good when its a payment gateway in the iframe, customers can loose confidence quite easily.
I am having an issue with this working in fancybox (www.fancybox.net). The fancybox uses an iframe so this works to a degree. The only problem is that once the page is loaded within the fancybox the css is not removed and the content remains hidden.
Is anyone familiar with fancybox enough to help me out? I’m new to javascript as well and I am sure it is a simple tweak that will fix this, but I am not sure where to start.
How can I add this code to my page? Do I need to insert within tags? Or tags??
I’m trying to have this work on an iframe embedde in a scene within a Hype (http://www.tumultco.com/hype/) site. The page with the iFrame is accesed as a scene and therefore the page doesn’t exactly ‘load’.
The iframe link is added within an inner HTML window.
Can I add this code elsewhere?
If not what other answer above best suits, perhaps adding custom CSS inside or alongside the iframe code?
Thanks!
Hi Chris. Thanks for helping. I pasted the code into the head as you say. The flash is gone but the video as well. Only hear audio. Why?
Regards,