<<< First Post - Welcome!


The Point of Natural Selection >>>


Wednesday,  01/01/03  01:56 AM

This site uses frames.  Why?  Because pages load faster.  Really.  Plus, the header stays at the top, and the navigation stays at the right, even if you have a long article which scrolls.  It is simply cooler.

Now, there are some drawbacks to using frames, but they can all be dealt with.  And this site deals with them.  Here are the drawbacks:

  • Each page doesn't have its own permanent link.
  • Each page doesn't have its own title.
  • Old browsers don't render frames correctly.
  • Non-standard browsers don't render frames at all.
  • Search engines can't index framesets very well.

These are important problems.  With a little work you can work around all of them and deliver a site to your visitor which is fast and works.  If you'd rather not do the work then avoiding frames is probably best.  But the work isn't that bad, and the remainder of this page explains what to do.

There are two main things you must do to make a site with frames work:

  1. Create a way for each page to be rendered without frames. 
  2. Create a way for a top-level URL to be associated with every content page.

The following paragraphs discuss these changes in more detail...

Render pages without frames

One obvious way to render pages without frames is to have two versions of every page, one designed to fit into your frameset, and one which is a "no frames" version with the header and navigation pages embedded alongside the content.  This isn't the most elegant solution, however; it involves a lot of care and ongoing work to keep the two sets synchronized.

A better way is to create a script which converts a "frames" version of each page into a "no frames" version, by rendering a page which has the header and navigation embedded.  This site has a script named noframes.cgi which does this. 

The trick to creating this script is to use the PATH_INFO environment variable, which is set to the part of the URL "beyond" the script in the path.  So a URL like /noframes.cgi/articles/frames.html will have PATH_INFO set to /articles/frames.html.  The noframes.cgi script simply uses this value to create the requested page with header and navigation embedded.

Here is the meat of the noframes.cgi script:

function body {
        sed -n "/^<body/,/^</body/p" "$1" |
        egrep -v "^<body|^</body" |
        sed "s/index.cgi/noframes.cgi/g" |
        sed "s|href="/|href="|g;
body "header.html"
echo "<table><tr><td valign=top>"
body "$1"
echo "</td><td valign=top>"
body "nav.html"
echo "</td></tr></table>"

If you are not a shell script aficionado, I'll try to explain briefly what's going on here; the same thing could be done in any other scripting language or even with a CGI program. 

The core is a function named "body" which takes an HTML page, extracts the part between the <body> and </body> tags, and edits it a little bit.  The editing consists of modifying references to index.cgi into references to noframes.cgi (more on this later), and modifying all HREF URLs so they include index.cgi.  For example, an HREF to "articles/frames.html" is converted to "noframes.cgi/articles/frames.html".  This turns all the "frames" links into "no frames" links.

The outer logic is to create an HTML table which places the header, navigation, and content page appropriately.  Each of these pages' content is included with the "body" function.  The result is a page which contains the header, navigation, and content all embedded together; a "no frames" page.

See the little "no frames" link over there on the right?  Click it and you'll enter the parallel universe of this site without frames.  If you get tired of waiting for pages to reload, you can click the "frames" link on the right to get back.

Top-level URLs for every content page

To have a top-level URL associated with every content page, you must create a script which generates your frameset.  This site has a script named index.cgi which performs this logic.  The PATH_INFO trick is used by this script also; so a URL like /index.cgi/articles/frames.html generates a frameset with the page /articles/frames.html in the content pane.

These "frames" URLs enable a permalink to every page within the site, as part of the frameset.  Each article and post has a permalink associated with it.  Visitors can use these links to bookmark particular content, email them to friends, etc.

Every frameset can [and should] include a <noframes> section.  The contents of this section can be generated by the noframes.cgi script discussed above.  If a browser can't support frames, it uses the "no frames" version of the page.  In addition to supporting browsers which can't render frames, this also gives search engines a non-frame version of your site to crawl.

Okay, with these things done, where does this leave us?  There are a few other little things to do; let's re-examine the drawbacks noted above...

Each page doesn't have its own permanent link

This is pretty important, especially with a weblog.  Essentially every article and post should have a "permalink" in its header which contains a link that re-renders the page.

As noted above, the index.cgi script makes this possible.  Now every page has a permalink, and everyone's happy.

Each page doesn't have its own title

This is a nuance, but an important one.  The solution is to set the title for each page differently from normal.  The usual way would be:

<head><title>my page's title</title>...

This works great if the page is the "top" page, but doesn't work at all if the page is in a frameset.  However, you can also set the title this way:

<body><script>top.document.title="my page's title"</script>...

This works even if the page is not the "top" page.  Leave the <title> tags in the <head>, however, because they are used by search engines!

Old browsers don't render frames correctly

Browsers which try to deal with frames but mess them up are unfortunate.  This used to be a bigger problem in the past, but for a long time now the "current" versions of IE, Netscape, and other popular browsers (e.g. Opera) all deal with frames properly and consistently.  (This is why Netscape 7 is so important, not so many people use it, but people with technical or political reasons for avoiding IE now have an IE-compatible choice.)

The best way to handle this problem is to give users a "no frames" choice.  If they click on it they'll get the "no frames" version of your website and be happy.  Meanwhile the majority of your users who will be using a standard browser which works perfectly with frames won't be penalized.

Non-standard browsers don't render frames at all

There are non-standard browsers which for technical or other reasons can't render framesets.  Examples include WebTV and other TV-based browsers such as game consoles, cell phones, PDAs, and specialized browsers used by people with disabilities.  Browsers which can't deal with frames at all will use the <noframes> version of the home page (see above) and they'll be happy.  Those users will simply enter your "noframes" world. 

Search engines can't index framesets very well

This is true and important.  Search engines use programs called "spiders" which "crawl" a website, following links and indexing pages.  Remember the index.cgi script mentioned above?  Since it generates a frameset with the "no frames" version of each page embedded between <noframes> tags, search engine spiders can access the information and all is well.

You generally want spiders to exclude your header and navigation pages from their indices, even though you want them to follow links on them.  Put the following tag in each of your header and navigation pages:

<meta name="ROBOTS" content="NOINDEX">

This tells spiders "don't index this page", but they'll still follow links from them.

Yeah, it is a little more work to support frames.  But it isn't impossible, and the result is well worth it.  Just try clicking around on this site and notice how fast the pages load.  It really makes a difference.

[ Later - I made a couple of frames-related enhancements, please click here for details... ]

[ Still Later: I ran a survey, and nobody liked my frames, so I got rid of them. (Simple is good...) ]

P.S. I'm happy to share this code - shoot me email if you're interested.