Dynamic Force frame Effect for Iframes

 
Published on 2002-06-26 by John Collins.

Working with frames on your site can be a real nuisance. If a user accesses a page directly, via a bookmark, link or search engine, they will by-pass your 'frameset' page and go straight to the content, effectively removing your entire site interface: side-bar, top-bar, logo etc. One way to avoid this from happening is to use JavaScript to 'force' your web pages into the frameset page. There are many good force-frame scripts available on the Net, but most are for the traditional frameset arrangement, but what if you use the more flexible iframe alternative?

Personally, I hate framesets and I find them a pain to work with. Iframes, on the other hand, and much more straight forward to work with. Originally introduced by Microsoft in Internet Explorer to offer an alternative to the ilayer offering from Netscape, both Netscape 6+ and Mozilla 1+ now fully support iframes so compatibility is no longer an issue.

Setting up the Script

A good force-frame script should carry out the following functions:

  1. A visitor accessing a content frame should be re-directed to the main home page.
  2. When the visitor is re-directed, the content page that they initially visited should be reloaded into the content frame of the home page.

At this stage this is perhaps best understood with a demonstration. For this demonstration, we have four files:

File Description
index.html The main home page file, containing the iframe.
framed.js The JavaScript file that contains the force-frame script, this will be linked into all of the content pages.
page1.html An example content page.
page2.html Another example page.

Here are the links to the three HTML pages:

index.html
page1.html
page2.html

Notice how the content pages are framed even when directly accessed? This is due to the force-frame script contained in 'framed.js'.

The Script

Here is the script from 'framed.js' in full:

pageLoc = self.location;
pageAdd = top.location;
 
if (pageLoc == pageAdd) {
    contentSrc = escape(pageLoc);
    contPage = 'index.html?' + contentSrc;
    top.location.href = contPage;
}

This script compares the document's URL (Uniform Resource Locator) with that of the URL in the browser window, and if they are the same, then it is determined that the page is not loaded into a frame as it should be. The script then combines the URL for the home page (in this case 'index.html') with the URL of the content page (pageLoc) and separates these two with a question mark (?). This new location is then loaded to replace the current location.

Managing the Iframe

Now that you have sent this information to the 'index.html' page, how is it processed? Here is the code in full from that page:

<html>
 
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Home Page</title>
 
</head>
 
<body bgcolor="gray">
 
<script language="javascript">
// writes in the iframe
var contPage = (location.search.substring(1))? location.search.substring(1) : 'page1.html';
 
var myDomain = "my-site";
// now check to see that myDomain is part of the content page string
var contValid = contPage.search(myDomain);
 
if (contValid == -1)
    contPage = "page1.html";
else
    contPage = unescape(contPage);
 
document.write('<center>');
document.write('<iframe src="'+contPage+'" name="content" height="300" width="400">');
document.write('</iframe>');
document.write('</center>');
 
</script>
 
<a href="page1.html" target="content" style="color:white;">Page 1</a>
<a href="page2.html" target="content" style="color:white;">Page 2</a>
</body>
</html>

Rather than using HTML for setting up the iframe, we use JavaScript to write it in. This allows for the frame source to become variable, i.e. the contPage variable.

The 'page1.html' page is the default page that is loaded into the frame if the index.html page is accessed directly, that is if there is no question mark (?) in the address bar. You can change this to match your default page.

Securing the IFrame Page Source (amended 5-May-2004)

A reader of this article pointed out to me that it is possible to supply URL's of pages from remote sites to this script, by simply typing in the address after the question mark in the address bar. To counter this problem, I have modified the script above to include a check against the domain of the web site.

The myDomain variable is used to contain the domain name of your web site. It does not have to be complete, for example here I am only using "my-site", and not "my-site.com" as the .com and .org equivalents are also valid. The script will now search the contPage variable for the domain string, if it is not found, -1 is returned and you know the URL supplied is invalid. All other integer values returned will be the position of the myDomain string within the contPage string.

Now all we have to do is load a default page when an invalid one is supplied, in this case page1.html, for example:

This will try to load Google into the iframe!

...but of course will not work, as the URL does not contain the string myDomain (my-site), so you get page1.html instead. However this will work:

page2.html

...because page2.html sits on the same domain as index.html, so myDomain will be present in the URL of page2.html. Thanks to Michael Borum for pointing out this bug to me, hopefully this should resolve the issue.

Conclusion

Of all the DHTML features contained within this site, I find this one the most useful. It now becomes possible for the user to store the URL for a particular page on the site for returning to later, a feature that would not be possible with HTML alone. Furthermore, it allows site managers to e-mail specific URL's for new content to their friends, business contacts or to a mailing list.

For demonstration purposes only, here is another example of the script containing a timer that slows down the reload to 3 seconds, which makes it much clearer to understand what is going on:

timed-demo.html


Updated 2020 : note that the above post is out-of-date, given this post was originally published in 2002, but is left here for archival purposes.