Last Comment Bug 255754 - body's offsetTop and offsetLeft values are incorrect when body has borders
: body's offsetTop and offsetLeft values are incorrect when body has borders
Status: NEW
INVALID?: see comment 10; for workaro...
: testcase
Product: Core
Classification: Components
Component: DOM (show other bugs)
: Trunk
: x86 Windows 2000
: -- normal with 2 votes (vote)
: ---
Assigned To: Nobody; OK to take it and work on it
:
: Andrew Overholt [:overholt]
Mentors:
Depends on:
Blocks: 196779
  Show dependency treegraph
 
Reported: 2004-08-16 04:19 PDT by Mikhail
Modified: 2013-04-04 13:53 PDT (History)
7 users (show)
See Also:
Crash Signature:
(edit)
QA Whiteboard:
Iteration: ---
Points: ---
Has Regression Range: ---
Has STR: ---


Attachments
Testcase built from reporter's code (slightly adapted, modified) (4.19 KB, text/html)
2004-12-22 17:12 PST, Gérard Talbot
no flags Details
DOM inspector reporting body's offsetLeft, offsetTop and offsetParent values (7.16 KB, image/png)
2004-12-22 17:20 PST, Gérard Talbot
no flags Details
test case (1.05 KB, text/html)
2009-05-26 13:48 PDT, Aharon (Vladimir) Lanin
no flags Details

Description Mikhail 2004-08-16 04:19:58 PDT
User-Agent:       Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; .NET CLR 1.1.4322)
Build Identifier: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a3) Gecko/20040813

After the page is loaded, the right-bottom corner gray DIV is visible (must 
not). Seems that offsetTop and offsetLeft values are incorrect for the body 
element.

Reproducible: Always
Steps to Reproduce:
1. Create a page:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML><HEAD><TITLE></TITLE>
<script>

function getTop(o) {
   var y = o.offsetTop;
   while (o = o.offsetParent)
      y += o.offsetTop
   return y
}

function getLeft(o) {
   var x = o.offsetLeft;
   while (o = o.offsetParent)
      x += o.offsetLeft
   return x
}

function setPos() {

   var d1 = document.getElementById('div1');
   var d2 = document.getElementById('div2');

   d2.style.top = getTop(d1)+'px';
   d2.style.left = getLeft(d1)+'px';

}
</script>
<style>
body {
   border: solid 2px black;
}
</style>
<BODY onload="setPos()">

<div id="div1" 
style="position:absolute;top:100px;left:100px;width:50px;height:50px;background-
color:silver">
Text
</div>

<div id="div2" 
style="position:absolute;top:100px;left:100px;width:50px;height:50px;background-
color:yellow;z-index:2">
Text2
</div>

</BODY></HTML>

2. Load the page.
Actual Results:  
After the page is loaded, the right-bottom corner gray DIV is visible.
The DOM Inspector shows that offsetTop and offsetLeft properties are set to the 
border's width value resulting in incorrect position calculation.


Expected Results:  
The gray layer must not be visible: offsets must be correctly adjusted.
Comment 1 Gérard Talbot 2004-08-16 19:54:36 PDT
According to 
Measuring Element Dimension and Location
http://msdn.microsoft.com/workshop/author/om/measuring.asp
offsetTop value does not include the offsetParent's border. Mozilla tries to
follow MSIE's DHTML object model here.
I checked your code with a few modifications, and the offset you see comes from
the border-width of the body node.
Comment 2 Gérard Talbot 2004-08-16 20:36:47 PDT
I must say that MSIE 6 treats abs. pos. elements differently as the picture
given at http://msdn.microsoft.com/workshop/author/om/measuring.asp
I opened a bugfile (bug123313) at Opera on this myself a few months ago. So I
feel awkward here.

http://www10.brinkster.com/doctorunclear/BrowserBugsSection/Opera7Bugs/OffsetParentRelatedBugs.html
Instructions: Mouse over the white-background abs. pos. <p> and results will show:
offsetParent tagName in Mozilla 1.8a3 and Opera 7.54: BODY
offsetParent tagName in MSIE 6 SP1a: HTML

So, there is a discrepancy here on the way to support offsetParent.

CSS2.1 says: 
"The containing block for a positioned box is established by the nearest
positioned ancestor (or, if none exists, the initial containing block)"
http://www.w3.org/TR/CSS21/visuren.html#q28

offsetParent according to MSDN: Retrieves a reference to the container object
that defines the offsetTop and offsetLeft properties of the object.

offsetTop Property according to MSDN: Retrieves the calculated top position of
the object relative to the layout or coordinate parent, as specified by the
offsetParent property.

Both MSDN definitions for offsetTop and offsetParent are somewhat circular.
Comment 3 Mikhail 2004-08-17 01:00:23 PDT
(In reply to comment #2)
http://www10.brinkster.com/doctorunclear/BrowserBugsSection/Opera7Bugs/OffsetPar
entRelatedBugs.html
> Instructions: Mouse over the white-background abs. pos. <p> and results will 
show:
> offsetParent tagName in Mozilla 1.8a3 and Opera 7.54: BODY
> offsetParent tagName in MSIE 6 SP1a: HTML
> So, there is a discrepancy here on the way to support offsetParent.

Taking into account the discrepancy between offsetParent support, I may suppose 
that Opera 7.54 would also show a part of the gray layer. But it does not, 
because offsetTop and offsetLeft for the body are zeroes there.
Comment 4 Gérard Talbot 2004-12-22 17:12:49 PST
Created attachment 169409 [details]
Testcase built from reporter's code (slightly adapted, modified)

Actual results in Mozilla 1.8a6 build 2004122106: yellow-background div is
positioned at coordinate (77, 77) in the content box of the body node. DOM
inspector reports that the body node's own offsetLeft and offsetTop is -23px
while saying that its own offsetParent is null. That does not make sense.

Expected results: yellow-background div should be positioned at coordinate
(100, 100) in the content box of the body node. Since offsetLeft, offsetTop and
offsetParent are MSIE's DHTML object model properties, then I think Mozilla
should follow MSIE 6 here.
Comment 5 Gérard Talbot 2004-12-22 17:20:27 PST
Created attachment 169410 [details]
DOM inspector reporting body's offsetLeft, offsetTop and offsetParent values

Picture of the offsetLeft, offsetTop and offsetParent values of the body node
when examining testcase of attachment 169409 [details] in DOM inspector. parentNode is
the root element (HTML node) and the offsetParent is (null) but in fact has to
be the ICB.
Comment 6 Gérard Talbot 2004-12-22 17:26:26 PST
Mikhail, I've reset this bug severity to minor since setting borders on the body
node and having to dynamically position an abs. pos. element according to
another element's offsetLeft/Top value is rather rare on the web. Adding
testcase and clean-report as keywords though.

CONFIRMING
Comment 7 Gérard Talbot 2005-05-05 15:30:53 PDT
I want to emphasize that there is no problem, no bug if people use

function getTop(o) {
   var y = o.offsetTop;
   while (o.offsetParent)
    {
      y += o.offsetTop;
      o = o.offsetParent;
    }
   return y
}

instead of

function getTop(o) {
   var y = o.offsetTop;
   while (o = o.offsetParent) // this instruction creates an unwanted side effect
      y += o.offsetTop
   return y
}

----

The bug with Mozilla here is that it returns an offsetLeft and offsetTop value
for an element that has NO offsetParent node.

Expected results: a node should return undefined for its offsetLeft value and
undefined for its offsetTop value if an element does not have an offsetParent
node (if offsetParent value is null) 
Comment 8 Olivier 2005-08-17 20:05:00 PDT
(In reply to comment #7)
> I want to emphasize that there is no problem, no bug

Please forgive me if I prove to be wrong, but IMHO there's something that look
silly in the offset properties.
Consider the following code:

<html>
<head>
<script>
function getTop(o) {
   var y = o.offsetTop;
   while (o = o.offsetParent) // this instruction creates an unwanted side effect
      y += o.offsetTop
   return y
}
</script>
</head>
<body style="margin: 0px;">
    <div style="border: 100px solid blue;"><div style="border: 50px solid
black;" onclick="alert(getTop(this));">Clickme</div></div>
</body>


You got an alert 150, which seems correct.
Now, add some "position: relative; top: 10px;" on one or another of the div.
You immediately loose the border-width of that element in the total count.


Please forgive my stupidity if I missed something, but how do we access the
screen position of an element if we can't compute it with offsets?

"since setting borders on the body
node and having to dynamically position an abs. pos. element according to
another element's offsetLeft/Top value is rather rare on the web."

Well, in my case, the problem is to dynamically set the height of a div
according to its top position and the coords of a click event...

Regards
- Olivier 
Comment 9 Olivier 2005-08-17 20:16:07 PDT
Sorry for the double post, but what I wrote was unclear and incorrect.
The first alert you got is 100 (and not 150), and this makes sense.

Now, replace the first div with:
<div style="position: relative; top: 10px; border: 100px solid blue; margin:
25px; padding: 25px;">

You'll get 60 (margin+padding+top)... where's the border?
Comment 10 Gérard Talbot 2005-09-03 18:24:34 PDT
> The bug with Mozilla here is that it returns an offsetLeft and offsetTop value
> for an element that has NO offsetParent node.
> 
> Expected results: a node should return undefined for its offsetLeft value and
> undefined for its offsetTop value if an element does not have an offsetParent
> node (if offsetParent value is null) 

This bug may be INVALID after all. The problem is that we are following MSIE
here and its unique implementation of offsetLeft, offsetTop and offsetParent
definitions. On this page, when viewed and tested with MSIE 6 SP2, 

http://www.gtalbot.org/BrowserBugsSection/MSIE6Bugs/OffsetValues.html

the offsetLeft and offsetTop correspond to the body margins and offsetParent
returns null. So, IMO, their implementations are incoherent otherwise their
definitions are incorrect. Either way, Mozilla can not implement incoherently
defined properties which are not even under its control.
Mozilla considers border around the body node when measuring offsetLeft and
offsetTop; MSIE 6 does not. MSIE 6 considers the margins around the body node
when measuring offsetLeft and offsetTop; Mozilla does not.

Anyway, I reported the whole thing though at:

http://channel9.msdn.com/wiki/default.aspx/Channel9.InternetExplorerBugs

so that if they ever better clarify their implementation - which I think is
ill-designed - then we can reopen this bug.

The workaround is still in comment #7.
Comment 11 Gérard Talbot 2005-09-04 20:57:47 PDT
I stumbled across this bug report regarding Firefox:
http://www.quirksmode.org/bugreports/archives/2005/08/Border_Bugs_in_Firefox_and_IE.html
and
http://crp2103.dyndns.org/endpoint/test.html
where Chad Plummer says "[Firefox and IE] don't take the border width into
account when calculating the offsetTop and offsetLeft JavaScript properties of
an element."

Comment 12 Anne (:annevk) 2006-05-22 04:22:51 PDT
http://dump.testsuite.org/2006/dom/style/offset/spec

I'm planning on writing something up that completely matches what IE does so every browser can do just that. Of course, there will be some issues I guess with position:fixed etc., but we can work those out.
Comment 13 Terje Rosenlund 2007-07-14 08:10:02 PDT
My planning is over and I have written an application that shows how any browser handles these issues. 

The application can be found at: http://home.no.net/trosen/bugzilla/CheckPosDim/CheckPosDim.html

It was written to document https://bugzilla.mozilla.org/show_bug.cgi?id=387922 
which I believe explains this and lots of other layout-related bugs
Comment 14 Garrett Smith 2008-02-17 20:34:48 PST
Marking NORMAL

comment #7 is not a workaround for the bug.

Finding an element's position is painful.

regarding the mentioned comment #12, no browser should even consider to implement it; it's wrong.
Comment 15 Aharon (Vladimir) Lanin 2009-05-26 13:37:44 PDT
Just wanted to chime in. This bug is still there, and now that IE8 has switched to the same offsetLeft & offsetParent model as Chrome 2, Safari 4, and Opera 9, there at last seems to be a standard developing.

When the body does not have position:relative or absolute, FF2 and FF3 put the left edge of the left margin of a position:absolute left:0 top-level element at the left edge of the left padding of the html element, i.e. the element goes inside the html's margin and border, but outside the body's margin and border. As long as this remains the case, the offsetLeft of a position:relative or position:static should include the body element's left border width, but should not include html element's left border width, so that top-level elements with absolute and non-absolute position at the same horizontal location get the same offsetLeft value. Same for offsetTop. FF2 and FF3 unfortunately still have it reversed for the borders - but get it right with the margins.

BTW, IE8, Chrome 2, Safari 4, and Opera 9 all put the left edge of the left margin of a position:absolute left:0 top-level element at the left edge of the window, i.e. outside the html's margin and border, and include the margin and border widths of both the html and body elements in the offsetLeft of non-absolute top-level elements.
Comment 16 Aharon (Vladimir) Lanin 2009-05-26 13:48:24 PDT
Created attachment 379747 [details]
test case

I've added a simple test case. Succeeds in IE8, Chrome 2, and Opera 9; fails in FF2 and FF3.

Note You need to log in before you can comment on or make changes to this bug.