Open Bug 481076 Opened 16 years ago Updated 2 years ago

offsetLeft and offsetTop wrong when position of parent node is not static


(Core :: Layout, defect)

Windows XP





(Reporter: boris, Unassigned)



(1 file)

User-Agent:       Opera/10.00 (Windows NT 5.1; U; en) Presto/2.2.0
Build Identifier: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv: Gecko/2009011913 Firefox/3.0.6 (.NET CLR 3.5.30729)

offsetLeft and offsetTop do not include the border width of the parent node if
the style property 'position' of the parent is not 'static'. In the test case
the style property 'position' is changed from 'static' to 'relative'. This
change makes Firefox (and Safari and Chrome) return different offsetLeft and
offsetTop values. If you add the border width of 15px to those values you get
the correct results again. If you open the test case in Internet Explorer and
Opera you'll see that they return the same values no matter what 'position' is
set to.

Reproducible: Always
Component: General → Layout
Product: Firefox → Core
QA Contact: general → layout
Version: unspecified → Trunk
I do not think that this is a bug. offsetLeft and offsetTop are relative to the client area of offsetParent. The client area is the area inside a element's borders and margin and scrollbars. However, the client area does include the padding. The offsetParent is the element's closest ancestor that has relative or absolute position (not static).

In your test case, once p becomes position:relative, it becomes the offsetParent of s. Thus s's offsetLeft is supposed to be 20: it counts p's padding (20), which is inside its client area, but not p's border, which is outside it.

When p is position:static, it is not supposed to be s's offsetParent. That honor goes to the body element. Then, s's offsetLeft is supposed to be 35, since that is how much s is inside the body's client area.

The reason that you get different results in IE when p is position:static is that IE for some very strange reason that I do not understand makes p the offsetParent of s despite p being position:static. If you make s position:relative, the body will become s's offsetParent, and its offsetLeft will become 35, same as in FF and Safari.
My explanation of IE's behavior is incorrect. Apperently, when p's position is static, s's offsetParent is (correctly) the body, and not p as I had stated. That's not the problem. The problem is that when p's position is relative, IE seems to makes s's offsetLeft relative to something other than p's client area. If you make p's position absolute instead of relative, IE starts behaving the same as Firefox and Safari. I am not sure why IE is behaving this way with position:relative.
Still more info on IE's buggy behavior: if you give p height:50px or even height:100%, s's offsetLeft becomes correct (relative to p's client area).
Why do you think it's a bug in IE? I thought other browsers supporting offsetLeft and offsetTop try to simulate IE's behavior as these properties have been invented by Microsoft? I don't know if there is a Microsoft specification which can be used to show that IE is wrong. If there isn't any I would expect that IE is implemented according to an internal Microsoft specification and we have to assume that IE's implementation is correct? Or is there a standard which defines offsetLeft and offsetTop?
First, let me clarify that I am not a Mozilla engineer, just a user that happened to come across this bug report because I was filing a somewhat similar one.

I think it's an IE bug because:
- There is no spec. That does not mean that whatever Microsoft did is what they meant to do and what they will continue doing in the next version. They are allowed to make mistakes.
- No other browser treats position:relative elements with no explicit height or width in this way.
- The current behavior makes no sense. If you play with it some more, you see that s's offsetLeft and offsetTop are actually relative to the body's client area, not p's, even though p is returned as the offsetParent. For example, if you put <br>'s before p, s's clientTop increases. If it looks like a bug, and it smells like a bug, it's a bug.
If there is no spec and we can't assume that Microsoft knows what they do then the behavior of non-standard properties depends on what? As the Mozilla developer center refers to MSDN my expectation so far is that MSDN is the spec and IE an implementation of the spec. 

Regarding other browsers: Opera 9 and 10 alpha behave like IE. And whether it makes sense is not really the question here. If it's a matter of making sense who guarantees that Mozilla developers won't change offsetLeft and offsetTop in the future if someone decides that something else makes sense? The behavior of offsetLeft and offsetTop is then even more debatable and could change at any time. 

As Mozilla took over offsetLeft and offsetTop from Microsoft it would definitely be helpful if offsetLeft and offsetTop do the very same thing as in IE. Otherwise we need to detect browser versions in Javascript and can't even use feature detection as after all the properties are called everywhere the same.
1. Add a <!DOCTYPE html> to the top of the test file to turn off quirks mode, and check it out in IE8. s.offsetLeft and offsetTop are now relative to p when p is position:relative, as in FF and Safari, but not as in IE7. However, s's offsetLeft now includes its own border - unlike any other browser, including IE7, and as far as I am concerned, a new bug...

2. Opera 9 is NOT doing the same thing as IE7. It only looked that way because you set the body padding and margin to 0. Opera has its own bug: it's counting p's border in s's offsetLeft.
I added the DOCTYPE declaration for HTML 4.01 Strict and compared the results: While IE 8, Opera 9 and 10 alpha calculate the same values no other browser does. But how does this help to figure out what Firefox is supposed to do? As long as MDC refers to MSDN web developers have to assume that Firefox tries to simulate IE's behavior? If Firefox doesn't this could be very well a documentation bug. It would just be great to know what to rely on. 

Regarding body padding and margin: I set them to 0 to overwrite default values in all browsers. Otherwise it's hard to compare the values as after all browsers might use different default values. Setting body padding and margin to 0 creates a uniform test environment.
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.