Making IE 5.5+ use position: fixed;

Navigation

Skip navigation.

Site search

Site navigation

Deprecated

This fix is deprecated and is no longer supported (meaning that I will not help you to get it working with your pages). It was only written to fill the gap while waiting for Internet Explorer to implement fixed positioning. That has now happened in IE 7. Although this fix can make it work in IE 6 as well, that is counter productive for the future of the Web. IE 6 is a major problem to Web developers (IE 7 is a problem as well, but for now, let's overlook that, since it does at least implement fixed positioning), and the sooner it stops being used, the better.

Instead of using this hack, users of IE 6 should be encouraged to upgrade to IE 7. Users who cannot upgrade to IE 7 (because IE 7 is not being released for most Windows operating systems) should use a better browser, such as Opera or Firefox. They have been abandoned by Microsoft.

What is position: fixed;?

position: fixed; is an alternative to position: absolute; position: relative; and position: static;.

position: fixed; is basically the same as position: absolute; except that when the user scrolls the page, the element does not scroll with it, it just says exactly where it was. There are many pages that want to use this in order to position logos or menus.

What is wrong with position: fixed;?

Well, ... nothing. The problem is that the most popular browser - Internet Explorer for Windows - does not understand it, and instead of reverting to position: absolute; which would be better than nothing, it reverts to position: static; as specified by the CSS standard. This has the same effect as having no positioning at all. Note that IE 7 from beta 2 upwards does support position: fixed; (if you use a document type declaration that triggers strict mode) so I will exclude IE 7 from this fix.

As a result, serveral people write scripts that use setInterval to reposition an absolutely positioned element every few miliseconds, or (ignoring Netscape 4) when the onscroll event is detected. This produces a slightly jerky effect. It would be better if the position: fixed; style could be applied in browsers that supported it, and browsers that didn't could use position: absolute; and JavaScript. Some authors use the > CSS selector to isolate Internet Explorer and leave the element positioned absolutely in that browser, without the scrolling effect.

div#fixme { position: absolute; left: 0px; top: 0px; }
body > div#fixme { position: fixed; }

It produces a reasonably nice effect, but it is even better when coupled with a JavaScript that checks if the position is 'absolute' using the currentStyle property, and then repositioning the element when the onscroll event is detected.

Can it be done any better

Well, possibly. It would be neater if it could be done with just CSS, and I have found a way to take things one step closer to that.

When Microsoft added their proprietary 'expression's to CSS in Internet Explorer 5, I jumped at the chance to use these to position the absolute element. Expressions should automatically update according to changes in the browser, such as scrolling the page, or resising the window.

div#fixme {
  left: expression( document.body.scrollLeft + 'px' );
  top: expression( document.body.scrollTop + 'px' );
}
body > div#fixme { position: fixed; left: 0px; top: 0px; }

But major disappointment. Due to a bug in Internet Explorer's interpretation of expressions, it does not update this, so it just stayed at 0,0.

However, while playing around with some CSS, I noticed something slightly odd. If I assigned the value to a variable, then used that to assign it to the expression inline, it did update in Internet Explorer 5.5 and 6. It is slightly jerky, but not as bad as many script driven positioning techniques.

top: expression( ( ignoreMe = document.body.scrollTop ) + 'px' );

Of course, in Internet Explorer 6, the variable is assigned to document.documentElement.scrollTop when in standards compliant mode, so I needed to check for this as well. IE 7 must also be excluded from the fix.

ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop

And we may want to position the element somewhere other than 0,0:

top: expression( ( 10 + ( ignoreMe = document.body.scrollTop ) ) + 'px' );

Of course, this also won't validate as CSS, so I prefer to put the extra CSS inside a conditional comment. This also allows lesser browsers like Netscape 4 to use the normal left and top positions.

<style type="text/css">
#fixme {
	/* Netscape 4, IE 4.x-5.0/Win and other lesser browsers will use this */
  position: absolute; left: 20px; top: 10px;
}
body > div#fixme {
  /* used by Opera 5+, Netscape6+/Mozilla, Konqueror, Safari, OmniWeb 4.5+, iCab, ICEbrowser */
  position: fixed;
}
</style>
<!--[if gte IE 5.5]>
<![if lt IE 7]>
<style type="text/css">
div#fixme {
  /* IE5.5+/Win - this is more specific than the IE 5.0 version */
  left: expression( ( 20 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );
  top: expression( ( 10 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );
}
</style>
<![endif]>
<![endif]-->

One of my readers also found a way to stop the effect being jumpy (with more details in a later email conversation), but note that it does not always work - the examples on this page are still jumpy if the fix is applied (another of my readers found how to get the fix to work on pages like this). However, you may find that it works for you.

How about another corner?

OK, so maybe you want to put it in the bottom-right corner. Well, in theory, you just substitute left for right, and top for bottom, and then you change the + signs to - signs at the start of the expressions. Would be nice if it was that simple. But it is not simple. IE gets the positioning completely wrong. It works until you scroll, and then it repositions it twice as far as it needs to. And if you try dividing by two, it does the same thing, but only updates the position every two pixels instead of every 1. Bah!

So it always needs to be positioned with respect to the top-left corner, like it or not. But we can still reposition it, checking its own size and the window size, and move it into the other corners. We can work out window size using the clientHeight property of the documentElement object in 'standards compliant mode' (What a load of rubbish! If IE was standards compliant, we wouldn't have to go through all of this stupidity in the first place - but I digress ...), and the body object in quirks mode (see the window size part of my JavaScript tutorial for more details). We can then get the size of the element itself using fixme.offsetHeight. This is IE's shorthand for the more normal expression:

document.getElementById('fixme').offsetHeight

Thankfully, the window and element size do not need any tricks to force them to update, but we will still need to do the check for standards/quirks mode.

The default setup uses the right and bottom properties, so browsers that support the standards correctly will work using them. Then in IE 5.5+, these will be reset to auto, and the left and top positions will be used instead. Remember that for right or bottom emulation like this, the offsets used in the expression must become negative.

<style type="text/css">
#fixme {
  /* Netscape 4, IE 4.x-5.0/Win and other lesser browsers will use this */
  position: absolute; right: 20px; bottom: 10px;
}
body > div#fixme {
  /* used by Opera 5+, Netscape6+/Mozilla, Konqueror, Safari, OmniWeb 4.5+, iCab, ICEbrowser */
  position: fixed;
}
</style>
<!--[if gte IE 5.5]>
<![if lt IE 7]>
<style type="text/css">
div#fixme {
  /* IE5.5+/Win - this is more specific than the IE 5.0 version */
  right: auto; bottom: auto;
  left: expression( ( -20 - fixme.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );
  top: expression( ( -10 - fixme.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );
}
</style>
<![endif]>
<![endif]-->

But why not use JavaScript to make it work in Netscape 4 too?

You can do that if you want. Just use this:

if( document.layers ) { setInterval ( 'document.layers.divID.top=window.pageYOffset;', 100 ); }

You could even do something with document.all to make it work in IE4 and 5.0/Win. But to be honest, I am getting very tired of seeing requests to make CSS work in Netscape 4. I know there are lots of things it can do, but let's face the facts; Netscape 4 just cannot cope in today's CSS driven web. It had a good life but it's dead now. Let it rest in peace.

F
i
x
 
M
e
F
i
x
 
M
e
 
T
o
o
This site was created by Mark "Tarquin" Wilton-Jones.
Don't click this link unless you want to be banned from our site.