Frames without frames


A word of caution

This method no longer works in IE6 under specific circumstances - please see the compatibility section for more information.


This series of pages demonstrate how to recreate all the goodness of frames with not a frame tag in sight. The source order of your elements can be as semantically and pedantically logical as you wish and you can use pixels, ems or percentages to position them. Essentially, this method emulates fixed positioning and the combination of top and bottom, left and right properties in IE, which as any fule knows, are broken under normal conditions.

Yes, yes, I know - you want to get to the nitty gritty, the actual frames without frames stuff. Just bear with me though. This page contains an explanation of how this method evolved, a half-hearted "Here comes the science part", and a breakdown of which browsers it's safe to use this method with.


I was knuckling down to make an all-singing, all-dancing demo expounding the wonders of Eric Bednarz's ghost in the box hack since the question "How can I produce frames-like results in CSS?" is a frequently asked question on css-discuss, when I stumbled accross a 2002 demo by Edwardson Tan (Columns of Galaxies) that went a long way to acheiving much the same effect but with absolutely positioned divs. As I perused Edwardson's code, I recalled Sven Tofte's groundbreaking max-width expressions in IE, and all of a sudden I saw the light. These pages are the result of that happy congruence.


Ah yes. Here comes the science part.

The xml prolog (that's the funny looking tag at the very top - <?xml version="1.0" encoding="iso-8859-1"?>) is needed for IE6 to display correctly - it may be possible to do without it but I can't be bothered to figure that out [1]. That means IE6 operates in quirks mode. On the bright side though, that means that there's no need to feed different values to different versions of IE. (Bizarrely, when these same techniques are applied to the ghost in the box method, we have to be in standards mode and so must leave the prolog out).

All elements that will act as frames (in these examples they're all trusty divs) should be absolutely positioned and have their overflow property set to auto (unless you know that the contents of the element will not exceed the element's size).

Next thing is set to set the body's autoflow to hidden - now all the absolutely positioned elements will stay firmly in place just as if they were set to be fixed. So far so good and not so very different from the demos mentioned in the inspiration blurb.

The trick is to use top and bottom, right and left properties in conjunction - modern browsers just do the right thing and sort out the height automatically. It's really that simple.

Except it isn't. This doesn't work in IE - if the top or left properties are set, then the bottom and right properties respectively get ignored.

The real trick (in addition to the one already mentioned) is to use dynamic properties, aka expressions.

"But surely," you protest, "expressions don't validate?" You're right - but there's nothing to stop us putting the relevant selector or stylesheet declarations within IE's conditional comments. So that's exactly what we do.

Let's take a simple example. If we have div#foo and want it to be 200 pixels wide, be positioned in the top left corner and to run down the entire left side to the bottom, then the following declaration is what's needed for the 'moderns':

    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 200px;
    overflow: auto;

Now we need to add the following declaration that only PC versions of IE can see:

    height: expression(document.body.clientHeight + "px");

document.body.clientHeight is the height of the viewport, so what we're doing is telling IE to position the div at the very top of the viewport and make it as tall as the viewport.

Pretty simple, huh? But what about div#bar that we want to span 50 pixels from the top to 100 pixels from the bottom, and from 75 pixels on the left to 150 pixels on the right? This is our starting point:

    position: absolute;
    top: 50px;
    bottom: 100px;
    left: 75px;
    right: 150px;
    overflow: auto;

Again we need to add an additional declaration that only PC versions of IE can see:

    height: expression(document.body.clientHeight - (50 + 100) + "px");
    width: expression(document.body.clientWidth - (75 + 150) + "px");

That is, the height is the height of the viewport minus the top and bottom values added together. The width works out exactly the same way, but with the left and right values subtracted from the viewport's width. (Of course, you could write 50 + 100 as 150 - I've just done it this way to make it explicit what's going on)

Mac IE5 is a problem child however (and personally my choice for the accolade of the new Netscape 4) because it makes a right old hash of the overflows when a specific height hasn't been set. The fix is relatively trivial though - make the page a traditional continuous scroller for Mac IE5 by suppressing the body's overflow:hidden and not absolutely positioning #content or #footer. Examine the code - you'll see what I mean.

On the following pages, you'll see how to use ems and percentages as your unit of choice should you wish. You'll also see how we can then reapply the lessons learnt here to the traditional ghost in the box hack and reclaim usability points lost in the absolutely positioned method, but, wouldn't you know, lose some others in the process.

The "frames" will usually have spaces between them to show more clearly how precisely they are positioned, but the snippets above are the entire deal. It's really that simple.


Works in IE6 (but see below), IE5.5, IE5.01, Firefox 0.8, Mozilla 1.6, Safari 1.1, Opera 7.23, Opera 7.5.

Due to problems with how Mac IE5 interprets heights, these demo pages have been mostly hacked to allow Mac IE5 to behave as a regular continuous scrolling page.

Operas 5 and 6 fail miserably (except on the fixed versions) but the CSS could easily be adjusted to make them behave the same as Mac IE5. Or not as the case may be.

IE6 Compatibility under XP2

Most seriously, this method went from rock solid to the much less impressive status of just likely to work in IE6. When Microsoft released XP2, it upgraded IE6 so that javascript expressions within CSS are not executed if, and only if, the zone which a page resides within's security is set to 'High'. In most versions of IE6 the security setting for the Internet zone is set to 'Medium' and so this method will continue to work for most users with IE6. However, unless you can guarantee that your users' security will not be 'High' (eg. your site is situated within a trusted zone) or if you do not mind that some users (in all likelihood, people behind a corporate firewall) will not see your site as you intended, I can no longer recommend using this method. A 'pure' javascript method, such as Andrew Clover's fixed.js, will probably be a better solution.

Standards Mode compatibility for IE 6

Actually I remembered that I knew how to fix it for IE6 in Standards mode all along. As I still haven't been bothered to incorporate that knowledge into the article, I'm sticking it here as an addendum.

A slightly more complicated expression is required since when IE6 is in standards mode, document.body.clientHeight returns 0 and you have to use document.documentElement.clientHeight instead (the situation is the reverse in quirks mode). Of course, lesser versions of IE don't return a value for that so what has to be used is a conditional expression like:

(document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight)

An example of this can be seen on this adjusted version of the basic layout

Alternatively, Leif Olsen wrote to tell me of another way to get IE6 to display correctly in standards mode.

Just add, "body { height: 100%; }", to your css. In addition you have to feed the new ghost in the box to ie6 expressions

I haven't tried this myself since I don't find the expression above too scary, but for those who do, I thought it worth mentioning.


Paul Bukhovko translated the article into Belorussian - Frames without frames- Belorussian version

Next: Basic layout


  1. Introduction
  2. Basic layout
  3. Using ems
  4. Using percentages
  5. Using fixed rather than absolute
  6. Interlocking - Can regular frames do this?
  7. What about iframes?
  8. Scalable with centered header and footer
  9. Scalable with centered header and footer (and no expressions) - a reprise
  10. Scalable again - but fixed
  11. Examples

CSS Stuff index | XHTML | CSS