Behavior test for position:fixed

H

Helbrax

I am working on a project that needs to use use the value of "fixed"
in the "position" property of the style element for an html object.
However, IE6 doesn't support "position:fixed", so I need to switch to
"position:absolute" instead if it isn't supported.
Rather than do a crude test for IE6(via browser sniffing, or inference
based on supported features/quirks), I'd rather do a behavior test to
see if "position:fixed" is being reported properly. The only problem
is, I'm not sure how to go about doing it.
I can create a div, set it's style position to "fixed" and set it's
left property to say, 100px, then test the elements offsetLeft
property. This actually works(ie6 reports 0, other browsers report
the actual offset). However, I'm not sure how widely supported
offsetLeft is, and I don't want to fall back to "absolute" positioning
when "fixed" would work, just because offsetLeft isn't working as
intended(or not available at all).
Any thoughts on how to do this?
 
E

Erwin Moller

Helbrax schreef:
I am working on a project that needs to use use the value of "fixed"
in the "position" property of the style element for an html object.
However, IE6 doesn't support "position:fixed", so I need to switch to
"position:absolute" instead if it isn't supported.
Rather than do a crude test for IE6(via browser sniffing, or inference
based on supported features/quirks), I'd rather do a behavior test to
see if "position:fixed" is being reported properly. The only problem
is, I'm not sure how to go about doing it.
I can create a div, set it's style position to "fixed" and set it's
left property to say, 100px, then test the elements offsetLeft
property. This actually works(ie6 reports 0, other browsers report
the actual offset). However, I'm not sure how widely supported
offsetLeft is, and I don't want to fall back to "absolute" positioning
when "fixed" would work, just because offsetLeft isn't working as
intended(or not available at all).
Any thoughts on how to do this?

Hi,

I had the same problem last week, and found the following test.
http://yura.thinkweb2.com/cft/
Look up: IS_POSITION_FIXED_SUPPORTED

function isPositionFixedSupported() {
var isSupported = null;
if (document.createElement) {
var el = document.createElement("div");
if (el && el.style) {
el.style.width = "1px";
el.style.height = "1px";
el.style.position = "fixed";
el.style.top = "10px";
var root = document.body;
if (root && root.appendChild && root.removeChild) {
root.appendChild(el);
isSupported = el.offsetTop === 10;
root.removeChild(el);
}
el = null;
}
}
return isSupported;
}

This function only works if document.body is present.
I am not sure if this test is elegant. It worked on the few browsers I
could test on (including horrible IE6).

I hope this helps. (If the above test is broken/bad somehow, I am sure
somebody will correct it.)
Good luck.

Regards,
Erwin Moller

--
"There are two ways of constructing a software design: One way is to
make it so simple that there are obviously no deficiencies, and the
other way is to make it so complicated that there are no obvious
deficiencies. The first method is far more difficult."
-- C.A.R. Hoare
 
H

Helbrax

Hi,

I had the same problem last week, and found the following test.http://yura.thinkweb2.com/cft/
Look up: IS_POSITION_FIXED_SUPPORTED

function isPositionFixedSupported() {
   var isSupported = null;
   if (document.createElement) {
       var el = document.createElement("div");
       if (el && el.style) {
           el.style.width = "1px";
           el.style.height = "1px";
           el.style.position = "fixed";
           el.style.top = "10px";
           var root = document.body;
           if (root && root.appendChild && root.removeChild) {
               root.appendChild(el);
               isSupported = el.offsetTop === 10;
               root.removeChild(el);
           }
           el = null;
       }
   }
   return isSupported;

}

This function only works if document.body is present.
I am not sure if this test is elegant. It worked on the few browsers I
could test on (including horrible IE6).

I hope this helps. (If the above test is broken/bad somehow, I am sure
somebody will correct it.)
Good luck.

Regards,
Erwin Moller

--
"There are two ways of constructing a software design: One way is to
make it so simple that there are obviously no deficiencies, and the
other way is to make it so complicated that there are no obvious
deficiencies. The first method is far more difficult."
-- C.A.R. Hoare

Hi, thanks for that. It looks like the same technique I am using. My
only worry is the use of offsetTop/Left. However, that may be the
only way to test for this.
 
T

Thomas 'PointedEars' Lahn

Helbrax said:
I am working on a project that needs to use use the value of "fixed"
in the "position" property of the style element for an html object.
However, IE6 doesn't support "position:fixed", so I need to switch to
"position:absolute" instead if it isn't supported.
Rather than do a crude test for IE6(via browser sniffing, or inference
based on supported features/quirks), I'd rather do a behavior test to
see if "position:fixed" is being reported properly. The only problem
is, I'm not sure how to go about doing it.

You do not need to do that. Your stylesheet declarations only need to be

position: absolute;
position: fixed;

If `fixed' is supported, it will be used; otherwise `absolute' will be
used. This works for other properties as well.


PointedEars
 
R

RobG

On Jan 19, 1:43 am, Erwin Moller
[...]
function isPositionFixedSupported() {
   var isSupported = null;
   if (document.createElement) {
       var el = document.createElement("div");
       if (el && el.style) {
           el.style.width = "1px";
           el.style.height = "1px";
           el.style.position = "fixed";
           el.style.top = "10px";
           var root = document.body;
           if (root && root.appendChild && root.removeChild) {
               root.appendChild(el);
               isSupported = el.offsetTop === 10;
               root.removeChild(el);
           }
           el = null;

If there was any point to the above statement, it should be moved to
after this block. If el.style returns false, el may have been created
and assigned but the above statement won't be executed.

Is the statement intended to prevent memory leaks from circular
references? Since el is local and not involved in a closure, a
circular reference can't happen. It will be destroyed when garbage
collection next runs, along with the variable object it belongs to.

Or is there some other reason?
 
E

Erwin Moller

Thomas 'PointedEars' Lahn schreef:
You do not need to do that. Your stylesheet declarations only need to be

position: absolute;
position: fixed;

If `fixed' is supported, it will be used; otherwise `absolute' will be
used. This works for other properties as well.

That is only a good solution in case position:absolute is an acceptable
fallback option.

Erwin Moller

PointedEars


--
"There are two ways of constructing a software design: One way is to
make it so simple that there are obviously no deficiencies, and the
other way is to make it so complicated that there are no obvious
deficiencies. The first method is far more difficult."
-- C.A.R. Hoare
 
S

Stevo

Erwin said:
Thomas 'PointedEars' Lahn schreef:

That is only a good solution in case position:absolute is an acceptable
fallback option.

Erwin Moller

Not necessarily. In JavaScript you can test if .style.position=="fixed"
and then execute your alternate logic.
 
E

Erwin Moller

Stevo schreef:
Not necessarily. In JavaScript you can test if .style.position=="fixed"
and then execute your alternate logic.

Hi,

I am not sure I understand you.
When on IE6 for example, that will happily return true.

Look at the following snippet:

<div id="testdiv"
style="position:fixed;left:0px;top:0px;width:100%;height:100%;">
This is testdiv
</div>

<script type="text/javascript">
var posFixedSupported =
document.getElementById("testdiv").style.position=="fixed";
alert(posFixedSupported ? "position fixed supported":"position fixed
not supported");
</script>

I guess that IE6 will simply compare the value for .style.position (as
set in the styledeclaration for the element) to "fixed" and find it is
the same.

Regards,
Erwin Moller


--
"There are two ways of constructing a software design: One way is to
make it so simple that there are obviously no deficiencies, and the
other way is to make it so complicated that there are no obvious
deficiencies. The first method is far more difficult."
-- C.A.R. Hoare
 
S

Stevo

Erwin said:
Stevo schreef:

Hi,

I am not sure I understand you.
When on IE6 for example, that will happily return true.

Look at the following snippet:

<div id="testdiv"
style="position:fixed;left:0px;top:0px;width:100%;height:100%;">
This is testdiv
</div>

<script type="text/javascript">
var posFixedSupported =
document.getElementById("testdiv").style.position=="fixed";
alert(posFixedSupported ? "position fixed supported":"position fixed
not supported");
</script>

I guess that IE6 will simply compare the value for .style.position (as
set in the styledeclaration for the element) to "fixed" and find it is
the same.

Regards,
Erwin Moller

Good point. I'll stop posting before I'm actually awake :)
 
H

Helbrax

You do not need to do that.  Your stylesheet declarations only need to be

  position: absolute;
  position: fixed;

If `fixed' is supported, it will be used; otherwise `absolute' will be
used.  This works for other properties as well.

PointedEars
--
    realism:    HTML 4.01 Strict
    evangelism: XHTML 1.0 Strict
    madness:    XHTML 1.1 as application/xhtml+xml
                                                    -- Bjoern Hoehrmann

The project does not use stylesheets. I need to create a function
that similar to "isFixedSupported". It isn't enough to simply put it
in a stylesheet, as the return from this function will also be used
for other things(like which events need to be bound to what, etc).
 
H

Helbrax

You do not need to do that.  Your stylesheet declarations only need to be
  position: absolute;
  position: fixed;
If `fixed' is supported, it will be used; otherwise `absolute' will be
used.  This works for other properties as well.

The project does not use stylesheets.  I need to create a function
that similar to "isFixedSupported".  It isn't enough to simply put it
in a stylesheet, as the return from this function will also be used
for other things(like which events need to be bound to what, etc).[/QUOTE]

Actually, I think I'm just going to go with my original assesment.
After looking around it seems to be the most reliable way to
accomplish this. Thanks to all who made suggestions!
 
T

Thomas 'PointedEars' Lahn

Helbrax said:
Thomas said:
You do not need to do that. Your stylesheet declarations only need to
be

position: absolute;
position: fixed;

If `fixed' is supported, it will be used; otherwise `absolute' will be
used. This works for other properties as well.
[...]

The project does not use stylesheets.

Oh really? What do you think "position: fixed" is?
I need to create a function that similar to "isFixedSupported".

Compare against the (computed) value of the property after you applied the
stylesheet, there is your isFixedSupported() implementation.


PointedEars
 
H

Helbrax

Oh really?  What do you think "position: fixed" is?

Let me clarify: The project does not use an external CSS file. Sorry
for the confusion.
Compare against the (computed) value of the property after you applied the
stylesheet, there is your isFixedSupported() implementation.

That's what I was doing in the first place. I just wasn't sure if it
was the right approach, or if the offset* properties were reliable
enough to use for a test.
 
D

David Mark

Helbrax schreef:




Hi,

I had the same problem last week, and found the following test.http://yura.thinkweb2.com/cft/
Look up: IS_POSITION_FIXED_SUPPORTED

function isPositionFixedSupported() {
var isSupported = null;
if (document.createElement) {
var el = document.createElement("div");
if (el && el.style) {
el.style.width = "1px";
el.style.height = "1px";
el.style.position = "fixed";
el.style.top = "10px";
var root = document.body;
if (root && root.appendChild && root.removeChild) {
root.appendChild(el);
isSupported = el.offsetTop === 10;
root.removeChild(el);
}
el = null;
}
}
return isSupported;

}

ISTM that this is making some bad assumptions. For one, the created
DIV must be position:static to start with (probably will be in most
cases) and offsetTop must _not_ be 10 to start with. What you really
want to check is for a _change_ in offsetTop.

And, as Thomas mentioned, checking the computed (or current in IE)
style solves 99% of the problem (or 100% if you can adjust your design
to suit). To solve the remaining 1% of the _general_ problem (IE
again), I came up with a really hack-y try-catch inside conditional
comments, which has been demonstrated to work with any IE/JScript
combination.
 
H

Helbrax

ISTM that this is making some bad assumptions.  For one, the created
DIV must be position:static to start with (probably will be in most
cases) and offsetTop must _not_ be 10 to start with.  What you really
want to check is for a _change_ in offsetTop.

And, as Thomas mentioned, checking the computed (or current in IE)
style solves 99% of the problem (or 100% if you can adjust your design
to suit).  To solve the remaining 1% of the _general_ problem (IE
again), I came up with a really hack-y try-catch inside conditional
comments, which has been demonstrated to work with any IE/JScript
combination.

Ok, so I tried something like the following. However, it returns true
on IE6. Am I doing this correctly? Should I be comparing against
offsetLeft? If so, that brings me back to one of my original
questions: How reliable are the offset* properties?.

function isFixedSupported() {
var el = document.createElement('div'); //I'm assuming this
is available for right now for testing purpose.
el.style.position = 'fixed';
el.style.left = '100px';
document.body.appendChild(el); //Ditto
if(window.getComputedStyle) {
return document.defaultView.getComputedStyle(el,
null).getPropertyValue('left') === '100px';
}
else if(el.currentStyle) {
return el.currentStyle['left'] === '100px';
}
else {
return false;
}
}
 
H

Helbrax

Ok, so I tried something like the following.  However, it returns true
on IE6.  Am I doing this correctly?  Should I be comparing against
offsetLeft?  If so, that brings me back to one of my original
questions:  How reliable are the offset* properties?.

function isFixedSupported() {
        var el = document.createElement('div');  //I'm assuming this
is available for right now for testing purpose.
        el.style.position = 'fixed';
        el.style.left = '100px';
        document.body.appendChild(el);  //Ditto
        if(window.getComputedStyle) {
            return document.defaultView.getComputedStyle(el,
null).getPropertyValue('left') === '100px';
        }
        else if(el.currentStyle) {
            return el.currentStyle['left'] === '100px';
        }
        else {
            return false;
        }

}

Ok, so after some digging it seems that the currentStyle object
doesn't return accurately in IE(big surprise). This is what I've come
up with so far, that relies on offsetLeft. Sadly, I'm not aware of
tall the browser quirks and pitfalls, so there is a good chance I'm
making assumptions that aren't valid.

function isFixedSupported() {
var el = document.createElement('div');
var styleType = (el.runtimeStyle) ? 'runtimeStyle' : 'style';
el[styleType].position = 'fixed';
el[styleType].left = '100px';
document.body.appendChild(el);
if(window.getComputedStyle) {
return document.defaultView.getComputedStyle(el,
null).getPropertyValue('left') === '100px';
}
else if(el.runtimeStyle) {
return el.runtimeStyle.left === (el.offsetLeft + 'px');
}
else {
return false;
}
}
 
D

David Mark

Ok, so I tried something like the following. However, it returns true
on IE6.

It lied. :)
Am I doing this correctly?

Did you change something?
Should I be comparing against
offsetLeft? If so, that brings me back to one of my original
questions: How reliable are the offset* properties?.

If they are there and numbers, they always mean something. If you
stick to GIGO tests, it doesn't really matter what that something is
exactly. ;)

As mentioned, the following is not such a test. It looks a lot like
the various 'inject and detect" tests from My Library, which vary in
quality. I know I have several in the legacy Offset branch that use
almost identical logic. But this is a stretch for testing whether
fixed positioning is supported.

A simple way to tell is to attach a scroll listener and then watch if
the offsetTop/Left properties change with the scroll position. If
they don't, remove the listener. If they do, you adjust for the
scroll position.
function isFixedSupported() {
var el = document.createElement('div'); //I'm assuming this
is available for right now for testing purpose.

You should not assume createElement returns anything. There are older
and crippled browsers out there that will return - for example - the
undefined value. (!)
el.style.position = 'fixed';

I could swear that some version of IE throws an exception if you try
that. Been ages since I tried it though. As hack-y as my mylib-
fix.js is, it has never failed me for any of the myriad IE versions
and setups (and it's something I rarely need), so I leave it alone. I
really should add an injection test (sort of) like this one for non-IE
browsers though (got to be at least a few out there that can't do
fixed positioning).
el.style.left = '100px';

el.style.position = 'static';
document.body.appendChild(el); //Ditto

That's an easier assumption.
if(window.getComputedStyle) {

No, check document.defaultView.getComputedStyle.
return document.defaultView.getComputedStyle(el,
null).getPropertyValue('left') === '100px';

Don't use getPropertyValue as it is broken as designed in some old
browsers. Just use cs['left'] and you don't need a strict comparison
here. And this test is meaningless here as well. What you want to
know is if the computed _position_ style is 'fixed'.
}
else if(el.currentStyle) {
return el.currentStyle['left'] === '100px';

Of course that will return true.
}
else {
return false;
}

}

So, as mentioned, you need to do something like this:-

var el = document.createElement('div'), body = document.body;
if (el && body) {
el.style.position = 'static';
el.style.top = '0px';
body.appendChild(el);
var oldOffsetTop = el.offsetTop;

try {
el.style.position = 'fixed';
if (oldOffsetTop && typeof el.offsetTop == 'number') {
return oldOffsetTop != el.offsetTop;
}
} catch(e) {
}

return false;
}

And, as mentioned, you can leave off the el = body = null line. There
was a time when I automatically inserted that at the end of each
feature test. I've come to realize it isn't necessary.
 
H

Helbrax

It lied.  :)

Obviously! :p

I was referring to my line of thinking.

If they are there and numbers, they always mean something.  If you
stick to GIGO tests, it doesn't really matter what that something is
exactly.  ;)
True.

You should not assume createElement returns anything.  There are older
and crippled browsers out there that will return - for example - the
undefined value. (!)

Again, this assumption was just for testing. In the final function, I
would certainly test for the existence of el before I try to use it's
properties. This function was just a test I was running in 3 browsers
to compare the results(IE6, IE7 , FF).
I could swear that some version of IE throws an exception if you try
that.  Been ages since I tried it though.  As hack-y as my mylib-
fix.js is, it has never failed me for any of the myriad IE versions
and setups (and it's something I rarely need), so I leave it alone.  I
really should add an injection test (sort of) like this one for non-IE
browsers though (got to be at least a few out there that can't do
fixed positioning).

That's entirely possible.
That's an easier assumption.

See earlier comment about assumption for testing only.
No, check document.defaultView.getComputedStyle.

Just out of curiosity, why is one more reliable than the other? Other
than someone may have already created a global getComputedStyle.
Don't use getPropertyValue as it is broken as designed in some old
browsers.  Just use cs['left'] and you don't need a strict comparison
here.  And this test is meaningless here as well.  What you want to
know is if the computed _position_ style is 'fixed'.
Ok.


So, as mentioned, you need to do something like this:-

var el = document.createElement('div'), body = document.body;
if (el && body) {
  el.style.position = 'static';
  el.style.top = '0px';
  body.appendChild(el);
  var oldOffsetTop = el.offsetTop;

  try {
    el.style.position = 'fixed';
    if (oldOffsetTop && typeof el.offsetTop == 'number') {
      return oldOffsetTop != el.offsetTop;
    }
  } catch(e) {
  }

  return false;

}

This return false in IE7, which supports position: fixed. Would
oldOffsetTop be evaluated as false, since it equals 0?
 
D

David Mark

Obviously! :p


I was referring to my line of thinking.


Again, this assumption was just for testing. In the final function, I
would certainly test for the existence of el before I try to use it's
properties. This function was just a test I was running in 3 browsers
to compare the results(IE6, IE7 , FF).


That's entirely possible.


See earlier comment about assumption for testing only.


Just out of curiosity, why is one more reliable than the other? Other
than someone may have already created a global getComputedStyle.

Because the getComputedStyle method is specified for the defaultView
object (and nothing is specified for window). It's entirely possible
that a browser would support the standard, but not the proprietary
method. As it is, code like the above works only by _coincidence_ as
window == document.defaultView in some browsers.
Don't use getPropertyValue as it is broken as designed in some old
browsers. Just use cs['left'] and you don't need a strict comparison
here. And this test is meaningless here as well. What you want to
know is if the computed _position_ style is 'fixed'.
Ok.



So, as mentioned, you need to do something like this:-
var el = document.createElement('div'), body = document.body;
if (el && body) {
el.style.position = 'static';
el.style.top = '0px';
body.appendChild(el);
var oldOffsetTop = el.offsetTop;
try {
el.style.position = 'fixed';
if (oldOffsetTop && typeof el.offsetTop == 'number') {
return oldOffsetTop != el.offsetTop;
}
} catch(e) {
}
return false;

This return false in IE7, which supports position: fixed. Would
oldOffsetTop be evaluated as false, since it equals 0?

Were you testing a quirks mode document? In that case, it should
return false.
 
H

Helbrax

Because the getComputedStyle method is specified for the defaultView
object (and nothing is specified for window).  It's entirely possible
that a browser would support the standard, but not the proprietary
method.  As it is, code like the above works only by _coincidence_ as
window == document.defaultView in some browsers.

Ahh. Makes sense. Thanks for that.

Were you testing a quirks mode document?  In that case, it should
return false.

Nope. XHTML Strict validated by w3. Just to check, I created a div
with inline styles and it is being rendered correctly. However, both
offsetLeft and oldOffsetLeft are the same. The same goes for IE6.
Firefox reports that fixed is supported correctly.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,072
Latest member
trafficcone

Latest Threads

Top