It’s really annoying when instead of linking directly to your site in a full browser window another site links using an <iframe> or <frameset> <frame>. There’s a really simple method to bust out of frames using Javascript but as I discovered yesterday if you also use iframes in your own site the commonly used frame buster needs some improvement.
Frame busting that doesn’t work
Before looking at how to do it correctly I’ll show how to do it incorrectly, simply because there are a lot of tutorials out there that use an old technique that doesn’t work anymore.
<script> // DO NOT USE THIS CODE, IT DOESN'T WORK if(top.location != location) { top.location = location; } </script>
The reason the above example won’t work is that if your site is contained within a frame from another site, your page cannot read the value top.location due to cross-domain issues.
In Internet Explorer, you’ll get the error message "Error: Permission denied" or "Access is Denied" depending whether trying to reference top.location or e.g. top.location.host.
Firefox will show something like "Error: uncaught exception: [Exception… "Could not convert JavaScript argument arg 0 [nsIDOMWindowInternal.alert]" nsresult: "0x80570009 (NS_ERROR_XPC_BAD_CONVERT_JS)" location: "JS frame :: … javascript file … :: <TOP_LEVEL> :: line 1" data: no]" for top.location.
Chrome and Safari will show "Unsafe JavaScript attempt to access frame with URL … top URL … from frame with URL … window url … Domains, protocols and ports must match." Interestingly the current version of Chrome will still allow access to it.
Basic frame busting Javascript
The correct way to bust out of frames without causing cross domain issues is this:
<script> if(top != self) { top.location = location; } </script>
But if you have frames in your own site…
I pushed out a new update to my running calendar website yesterday which loaded content into a lightbox in an iframe. With the break out of frame code as used above, as soon as the page loaded into the iframe it would bust out of the frame and load into the main window which defeats the purpose of putting the content into an iframe. So, enter…
Frame busting Javascript that doesn’t break out of frames on your own site
This version of the script compares the host of the topmost window with that of the current window. The catch is that accessing top.location.host will result in an error (as mentioned in the first section above).
To get around this, use try..catch exception handling and variable setting to determine whether or not the window is within a frame from another domain, like so:
<script> (function() { var externallyFramed = false; try { externallyFramed = top.location.host != location.host; } catch(err) { externallyFramed = true; } if(externallyFramed) { top.location = location; } })(); </script>
Note that I’ve put the code in an anonymous function so any variables used only have local scope and don’t affect any other code that might run.
Line 5 checks to see if the host of the topmost window is the same as the current window.
If they are the same, then the current page is either the topmost page or it’s in a frame from the same domain, so externallyFramed is set to false and nothing else happens.
If they are different and the browser allows it, externallyFramed is set to true and then the topmost window is replaced with this page’s location on line 11.
If they are different and the browser does not permit cross domain checking of the location object then an exception is triggered, externallyFramed is set to true on line 8 and the topmost window is replaced with this page’s location on line 11.
3rd party services you want don’t want to frame bust
Just one final note which was brought to my attention on Twitter by Keri Henare (tweet here) and not something I considered myself, but sometimes frame busting techniques can cause issues with other services such as Google Image Search.
Image Search presents your page with an overlay showing the image and frame busting would probably navigate the user away from Google’s service.
Three options as I see it 1) don’t frame bust, 2) ignore the issue (I don’t let Google index images on my sites anyway), or 3) target all links and forms to _top so when the user clicks or submits your site ends up in the topmost window.
To target all links to e.g. _top by default, see my use base target to target links instead of using Javascript post.