- From: Mike Wilson <mikewse@hotmail.com>
- Date: Mon, 28 Apr 2008 23:02:05 +0200
- To: "'Sylvain Galineau'" <sylvaing@microsoft.com>
- Cc: "'Www-style'" <www-style@w3.org>
Hi Sylvain, and sorry about the delay. > > 1) IE does it this way. > This is probably the main source of confusion on my side; my > strict-mode tests with IE7/IE8 show parent outer-border-edge > to element outer-border-edge; same with Opera. Safari and > Firefox behave as currently specified in CSSOM-View. Ok, I haven't seen this myself but it is possible that you are putting IE in another "mode" than I do. But could it be possible that your own example actually isn't getting the offsetParent you expect so the parent border is added because the parent element is actually traversed on the way to the real offsetParent? As has already been discussed, IE's hasLayout affects the offsetParent chain. IE's offset algorithm is also partly broken when hasLayout is not in effect. I guess this is because an element with hasLayout=false delegates its geometry calculations to an ancestor with hasLayout=true (this could recurse all the way up to BODY) and this opens up to bugs. In this respect I'd say that triggering hasLayout is what gets you closest to an expected (and standard) behaviour as elements will avoid IE's "layout optimization" and do full geometry calculations on each element level. Below are a few tests for illustration. You find the code at the end of this mail. Each test table shows offsetLeft/offsetParent in different situations. [1. code unchanged = all DIV.position=static] IE7 IE7 CB DIV.hasLayout false true div1 4/BODY 4/BODY BODY div2 39/BODY 33/div1 div1 div3 67/BODY 12/div2 div2 hasLayout=false: In the table above you can see that for hasLayout=false all the DIVs have an offsetLeft including all borders/padding/margin down to each element's border edge but this is because offsetParent=BODY for all the elements. BODY is the first ancestor with hasLayout=true and IE doesn't seem to want to do offset calcs against non-hasLayout nodes, which makes sense when knowing about hasLayout. The padding-edge to border-edge rule seems ok. hasLayout=true: When triggering hasLayout through "div {zoom:1}" you can see that the closest parent is chosen as offsetParent as each parent now hasLayout so IE can calc offsets against them. The offsetParent coincides with the Containing Block (CB) and the offsets are padding-edge to border-edge. [2. code + div2.pos=rel] IE7 IE7 CB DIV.hasLayout false true div1 4/BODY 4/BODY BODY div2 39/HTML 39/HTML div1 div3 67*/div2 12/div2 div2 *=bug hasLayout=false: When making div2 a positioning context we can see that this makes div3 choose div2 as its offsetParent. Though, offsetLeft still reports offset against BODY (67)! This is a bug and my guess is it's because the offsetParent doesn't have hasLayout. (Also note that div2 itself now uses HTML instead of BODY as its offsetParent. It seems IE skips over BODY and refers directly to HTML for elements with "top" positioning contexts.) The padding-edge to border-edge rule seems ok. hasLayout=true: With hasLayout on div2, div3 will now get a correct offset. div2 will include div1's border in its own offset as the offsetParent is now HTML. (Note that div2.offsetParent now deviates from CB.) The padding-edge to border-edge rule seems ok. [3. code + div1.pos=rel and div3.pos=abs,left/top=0] IE7 IE7 CB DIV.hasLayout false true div1 4/HTML 4/HTML BODY div2 39/div1 33/div1 div1 div3 10/div1 4/div1 div1 hasLayout=false: Just as in the previous test we have an offsetParent (div1) without hasLayout. This means both div2 and div3 will report an offset relative to BODY (bug) so will include div1's margin and border. The padding-edge to border-edge rule seems ok. hasLayout=true: The offsetParent div1 now hasLayout and offsets are correct. The padding-edge to border-edge rule seems ok. So, to sum up; if you want to avoid bugs and surprises I'd suggest you trigger hasLayout on your offsetParents. Let me know if you had other cases that don't follow the scheme presented here! You can read more on what properties trigger hasLayout here: http://www.brunildo.org/test/hh.html http://onhavinglayout.fwpf-webdesign.de/hack_management/ (Personally I tend to trigger hasLayout anyway in many cases for the main sections of pages, through overflow settings and such.) > > 2) It's compatible with CSS 2.1's positioning with left/top > > attributes for position:absolute elements. > > I e, if you have an absolutely positioned element that > > you assign > > left:10px > > to, then offsetLeft will also return 10 as the offset is > > measured from the same points (padding edge to border edge) > > as used by CSS positioning. Of course assuming here that the > > offsetParent and Containing Block elements are the same, > > which they usually are in standards-mode IE, but not in the > > current CSSOM proposal. > This is good background, thank you. Oops, my bad here: double-checking the CSS spec shows that absolute positioning uses padding edge to *margin* edge as offset points (have I been dreaming or what?). So it doesn't seem we can say there is a correlation here. The padding edge to border edge scheme I guess was invented as a zero offset means the elements' borders "touch". Anyone, please correct me if I'm wrong here. The relevant links are here: http://www.w3.org/TR/CSS21/visuren.html#position-props http://www.w3.org/TR/CSS21/visudet.html#containing-block-details Best regards Mike <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html> <head> <style type="text/css"> * { border: 0px solid gray; margin: 0; padding: 0; } #div1 { margin: 4px; border-width: 2px; padding: 1px; } #div2 { margin: 32px; border-width: 16px; padding: 8px; } #div3 { margin: 4px; border-width: 2px; padding: 1px; } /* Uncomment to trigger hasLayout: */ /*div { zoom: 1; }*/ /* Uncomment for test/table 2: */ /*#div2 { position: relative; }*/ /* Uncomment for test/table 3: */ /*#div1 { position: relative; } #div3 { position: absolute; left: 0px; top: 0px; }*/ </style> </head> <body> <div id="div1"> <div id="div2"> <div id="div3">div3</div> div2 </div> div1 </div> <script type="text/javascript"> function printOffsetData( elem ) { document.write( "Element: " + (elem.id || elem.tagName) + "<br>" ); document.write( "offsetLeft: " + elem.offsetLeft + "<br>" ); document.write( "offsetParent: " + (elem.offsetParent && (elem.offsetParent.id || elem.offsetParent.tagName)) + "<br>" ); document.write( "hasLayout: " + ((elem.currentStyle && "hasLayout" in elem.currentStyle) ? elem.currentStyle.hasLayout : "N/A") + "<br>" ); document.write( "<br>" ); } printOffsetData( document.documentElement ); printOffsetData( document.body ); printOffsetData( document.getElementById("div1") ); printOffsetData( document.getElementById("div2") ); printOffsetData( document.getElementById("div3") ); </script> </body> </html>
Received on Monday, 28 April 2008 21:03:00 UTC