PDA

View Full Version : [CSS] Fixed position crossbrowser



molendijk
04-19-2008, 09:14 PM
1) CODE TITLE: Fixed position crossbrowser

2) AUTHOR NAME/NOTES: Arie Molendijk

3) DESCRIPTION: This fixes 'position:fixed' for IE<7. There are already many fixes available on the Internet, so why producing yet another fix? The reason is that many of the fixes don't support non-quirks mode for IE, or disable the standard use of 'position: absolute', or produce unpredictable results when the doctype is changed (jdenny's fix at http://dev.jdenny.co.uk/css/ie_fixed.html), or produce flickering divs when the page is scrolled. This fix does not have any of these disadvantages. Greatly indebted to Anne van Kesteren (http://annevankesteren.nl/test/examples/ie/position-fixed.html) and, more so, to jscheuer1 (see posts below).
Note: it's only after I posted this that I found that at least two sites offer solutions for 'position: fixed' that are very similar to page 1 of the URL TO CODE: http://www.gunlaug.no/contents/wd_additions_15.html and http://www.webmasterworld.com/css/3308239.htm. My apologies to the authors of these sites for what might be seen as (but what was NOT) 'copying work of others'. Anyway, pages 3 - 5 are 'new' (pages 3-4: thanks to John Scheuer, who made the scripts).

4) URL TO CODE: http://molendijk.110mb.com/position_fixed_nonquirks/position_fixed_nonquirks.html

jscheuer1
04-20-2008, 05:56 AM
Seems to work fine in IE 5.5 and 6. I'm just wondering, is eval truly needed? In my experience, an external function can take care of this without eval:


function fixIEtop(num){
return document.compatMode && document.compatMode=='CSS1Compat'? documentElement.scrollTop+num+'px' : document.body.scrollTop+num+'px';
}

('px' should be added for standards compliance) could be on or linked to the page, then the expression could be:


top:expression(fixIEtop(200));

And a similar setup could be used for the left property, both of which functions would make using it several times on a site or page much easier.

In any case, this will fail if IE has javascript and/or (perhaps) Active X disabled. Other solutions that require only pure css will not have this problem, but (as you point out) could have other issues.

Also, loading a non-existent image for background might not be as good as using a transparent .gif.

molendijk
04-20-2008, 02:06 PM
John,
You are right about the eval. Instead of
top:expression(eval(document.compatMode && document.compatMode=='CSS1Compat') ? documentElement.scrollTop+200 : document.body.scrollTop+200); left: expression(eval(document.compatMode && document.compatMode=='CSS1Compat') ? documentElement.scrollLeft+5 : document.body.scrollLeft+5)you can have this:
top:expression(document.compatMode &&
document.compatMode=='CSS1Compat' ?
documentElement.scrollTop+200 : document.body.scrollTop+200);left: expression(document.compatMode &&
document.compatMode=='CSS1Compat' ?
documentElement.scrollLeft+5 : document.body.scrollLeft+5)
A step further, then, would be to take out 'expression' and to put that into a function, as you indicated.
But for some reason, I don't manage to get the function right. Any help on this would be greatly appreciated.
----
Arie.

molendijk
04-20-2008, 03:30 PM
Something like this works
<script type="text/javascript">
function fixIEtop(){
var pos = document.compatMode && document.compatMode=='CSS1Compat' ?
document.documentElement.scrollTop : document.body.scrollTop;
document.getElementById("side").style.position = "absolute";
document.getElementById("side").style.top = parseInt(pos + 125) + "px";
}
window.onscroll=fixIEtop;
</script>
but now the div flickers when the page is scrolled, and that is exactly wjat I wanted to avoid.
---
Arie.

jscheuer1
04-20-2008, 05:40 PM
The beauty of the expression is that it acts very much like pure css. But the expressions can become unwieldy at times, especially if they must be repeated several times. That is where a function comes in, like:


function fixedIE(tl, n){
var sc='scroll'+tl, d=document, c='compatMode';
return d[c] && d[c]=='CSS1Compat'? d.documentElement[sc]+n+'px' : d.body[sc]+n+'px';
}

Then the css could be:


#someid{
position:absolute;
top:expression(fixedIE('Top',200));
left:expression(fixedIE('Left',5));
}

However, this assumes that IE will continue updating the position when it is setup this way. If not, another way must be found, or the eval will still need to be used. To do this entirely in a function, with no expression, will almost certainly cause flickers and/or jumpiness, unless you use the function to assign the expression as style, rather than as a direct style update via javascript alone.

In any case, you are still depending upon javascript, perhaps Active X as well.

molendijk
04-20-2008, 06:25 PM
John, thanks very much for your last post. After having made some minor changes in your function, I was glad to see that things started to work.
As soon as I have the time, I'll work everything out and show you the result.
Thanks again,
Arie.

jscheuer1
04-20-2008, 10:27 PM
Actually what I had works 'as is', except for a typo that I just fixed. Here is a full demo:


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style type="text/css">
#someid {
position:fixed;
top:200px;
left:5px;
width:75px;
height:75px;
border:1px solid gray;
color:#ccc;
background-color:#666;
}
</style>
<!--[if lte IE 6]>
<script type="text/javascript">
function fixedIE(tl, n){
var sc='scroll'+tl, d=document, c='compatMode';
return d[c] && d[c]=='CSS1Compat'? d.documentElement[sc]+n+'px' : d.body[sc]+n+'px';
}
</script>
<style type="text/css">
body {
background:url(foo) fixed;
}
#someid {
position:absolute;
top:expression(fixedIE('Top',200));
left:expression(fixedIE('Left',5));
}
</style>
<![endif]-->
</head>
<body>
<div id="someid">
I'm Fixed
</div>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
<p>Other Content</p>
</body>
</html>

molendijk
04-20-2008, 11:43 PM
John,
Before I read your last post, I produced this (http://molendijk.110mb.com/position_fixed_nonquirks/position_fixed_nonquirks_scheuer.html) (inspired by your script). It's very similar to the code that you sent in your last post.
Thank you very much for your help.
---
Arie.

molendijk
04-21-2008, 12:47 AM
Added 2 pages explaining (i) how to do it without 'eval'; (ii) how to do it with javascript.
I honestly think that the end-result (page 3) is better than the IE-emulations for 'position: fixed' presented before this (thanks to John Scheuer for the great help).
---
Arie.

jscheuer1
04-22-2008, 11:40 AM
Well, if one is going to go the function route, and this actually makes quite a bit of sense if the content to be positioned fixed is script generated, one may as well use a function that will make the css part as simple as possible.

Now, this could perhaps be made more verbose, or even refined more to make the css even simpler, but this (includes error checking which returns 0 if the arguments are not as expected) is what I have so far for the function:


function fixedIE(tl, n, el){
var sc = 'scroll'+tl, d = document, c = 'compatMode',
b = d[c]&&d[c]=='CSS1Compat'? d.documentElement : d.body;
n = n-0; if(typeof n!='number')return 0;
if(/^(Top|Left)$/.test(tl))
return b[sc]+n+'px';
if(/^(Bottom|Right)$/.test(tl)&&typeof el=='object'){
tl = tl=='Right'? 'Left' : 'Top', sc = 'scroll'+tl;
var dim = 'client' + (tl=='Top'? 'Height' : 'Width');
return b[sc]+b[dim]-el[dim]-n+'px';
}
return 0;
}

The css may now be:


#someid {
position:absolute;
top:expression(fixedIE('Bottom',100,this));
left:expression(fixedIE('Right',15,this));
}


or as before for Top and Left:


#someid {
position:absolute;
top:expression(fixedIE('Top',100));
left:expression(fixedIE('Left',15));
}


The this keyword can be used with Top and Left, it won't hurt anything. One can use a Top and a Right or a Bottom and a Left if desired.

molendijk
04-22-2008, 12:50 PM
John, one more 'say thank to ..'. This works great.
---
Arie.

molendijk
04-22-2008, 08:20 PM
Added a page containing some results of a script made by John Scheuer.
---
Arie.

jscheuer1
04-23-2008, 12:23 AM
This is a rather fine point, but bears mentioning. In your version of my script, when you do:


function fixedIE(tl, n, el){
. . . .
var n = n-0;

Although it may look clearer than what I wrote:


function fixedIE(tl, n, el){
. . . .
n = n-0;

You are actually declaring a variable that has already been declared as an argument.

Since javascript is still a highly flexible and error correcting language, this will not (as far as I know) cause any problems. But, as is all but inevitable, as javascript becomes more like other programming languages, it may very well break a script.

A safe alternative would be to do something like:


function fixedIE(tl, n, el){
. . . .
var num = n-0;

This would make it clear that you are seeking to establish num (the name you choose isn't really critical, as long as it is unique to its scope, and preferably somewhat descriptive of its range of possible values) as (in this case) a number. But you would then need to refer to it as such (num) in the rest of the function.

molendijk
04-23-2008, 06:56 AM
You are actually declaring a variable that has already been declared as an argument.
Completely true. That slipped my attention. I'll correct that as soon as I've the time.
---
Arie.

molendijk
04-23-2008, 09:29 AM
Corrected an error in my version of the Scheuer-script for emulating 'position:fixed' in IE<7.
---
Arie M.

neelchauhan
04-23-2008, 12:45 PM
Not so good!

jscheuer1
04-23-2008, 01:23 PM
Not so good!

What's the trouble exactly?

molendijk
05-05-2008, 12:38 AM
5th May:
Updated the URL_TO_CODE. Added simpler IE-expressions that require Standard Mode. Made an inventary of possible values for 'position:fixed' in IE. Introduced simplifications that may affect the Scheuer-scripts for IE-fixed. Taken on the whole: the pages are more complete. IE<7 seems to be really 'fixed' now.
---
Arie M.

molendijk
05-08-2008, 12:16 AM
8th May:
Updated the URL_to_Code. Added some critical remarks about the Scheuer-scripts. They don't handle the difference between quirks mode and standard mode, in some particular cases.

molendijk
05-11-2008, 10:22 PM
12th May:
Updated the URL_TO_CODE. Replaced the crossbrowser css-page with a page that shows how to emulate 'position: fixed' in IE in both standard and quirks mode (identical css for both modes).

molendijk
05-14-2008, 10:35 PM
15th May:
Corrected some minor errors. Updated the crossbrowser css-page.
16th May:
Added a javascript function that lets the IE-expressions (for emulating 'position: fixed') do their job in a javascript-environment.

molendijk
05-20-2008, 08:03 PM
20th May:
Modified the css-page. Now it works in Opera too. So I guess I found a truly crossbrowser solution for 'position: fixed', at last.