- From: Garrett Smith <dhtmlkitchen@gmail.com>
- Date: Fri, 14 Mar 2008 17:44:26 -0700
- To: "Mike Wilson" <mikewse@hotmail.com>
- Cc: Www-style <www-style@w3.org>
On Fri, Mar 14, 2008 at 3:04 PM, Mike Wilson <mikewse@hotmail.com> wrote: > > Hi Anne, > > I have studied some of the differences between the various > approaches and made some comparison tables below. There are > lots of data here so please excuse (and inform me) if something > is not correct. The HTML file used for testing is at the end of > this mail. > Hi Chris, I've made an example script to run the test, included below. Aside from the bugs that occur in all FF/Op/Saf, there is a 1 clear, fundamental difference in the handling of offsetTop/Left when the offsetParent in question is BODY with position: relative. > offsetParent > ------------ > This is the offsetParent returned for the respective elements > in the example file per browser/spec: > > offsetParent for/in: IE7 FF2 CSSOM [CB] simple? > HTML null null null ICB null > BODY null null null HTML HTML > div1(pos=rel) HTML BODY BODY BODY BODY > div2a div1 div1 div1 div1 div1 > div2b div1 div1 div1 div1 div1 > div3a(pos=abs) div1 div1 div1 div1 div1 > div3b div2b div1 div1 div2b div2b > > Observations: > > 1) CSSOM differs from IE by letting div1 point to BODY instead > of HTML. > > Q: What was the rationale for this change? (I agree that it > is "cleaner" not to special-case children of BODY to > instead point to HTML, but IE is the mother of these > properties so...) It is no more of a special case for pointing to HTML than it is for pointing to BODY. If offsetParent would be null, then the fallback could be to use the root node (HTML). This is what IE seems to be doing. [snip] > > * The Firefox algorithm seems to be completely different and > I have no guess on how to interpret this. It is a bug. Firefox subtracts the border width. https://bugzilla.mozilla.org/show_bug.cgi?id=255754 > 3) As can be seen in both tables IE returns useful values for > BODY's offsetLeft property while CSSOM hardwires it to 0. > > Q: What was the rationale for this deviation from IE's > behaviour? Good question. > > 4) As can be seen in the upper table, CSSOM returns offsetLeft > = 67 for div1, which is the distance to the viewport edge or > margin edge of the |HTML| element, even though div1 reports > using BODY as offsetParent, thus: > div1.offsetLeft = <distance to viewport/HTML> > div1.offsetParent = BODY > It would be more consistent to use > div1.offsetLeft = <distance to HTML> > div1.offsetParent = HTML > or > div1.offsetLeft = <distance to viewport> > div1.offsetParent = null > or > div1.offsetLeft = <distance to BODY> > div1.offsetParent = BODY > > This change from IE's behaviour leads to returning an > offsetParent that isn't the element used when calculating > offsets, which is inconsistent. Good observation. However when BODY has position: relative, things are different. Firefox 2/Safari: testBodyStatic #div1 tagName offsetLeft offsetTop offsetParent DIV#div1......47............47............BODY#body testBodyRelative #div1 tagName offsetLeft offsetTop offsetParent DIV#div1......12............12............BODY#body IE: testBodyStatic #div1 tagName offsetLeft offsetTop offsetParent DIV#div1......67............63............HTML#html testBodyRelative #div1 tagName offsetLeft offsetTop offsetParent DIV#div1......12............8.............BODY#body Opera: testBodyStatic #div1 tagName offsetLeft offsetTop offsetParent DIV#div1......67............67............BODY#body testBodyRelative #div1 tagName offsetLeft offsetTop offsetParent DIV#div1......67............67............BODY#body Observations: testBodyRelative: 1) Firefox and Safari use BODY as offsetParent and derive their offsetLeft/Top values from BODY. 2) Opera: BODY is not special-cased Insight: For getting the position of an element: using offsetTop: position: relative can be added to the container, BODY. This makes body work like a "normal" offsetParent in all browsers except Opera. Garrett Smith Example HTML: (example js, writeUpTree.js below) <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html id='html'> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <script src="writeUpTree.js"></script> <title></title> <style type="text/css"> * { border-color: gray; border-style: solid; } html { margin: 4px; position: relative; border-width: 2px; padding: 1px; } body { font-family: verdana, arial, helvetica, sans-serif; position: relative; font-size: 77%; margin: 32px; border-width: 16px; padding: 8px; } div { height: 30px; overflow: hidden; text-align: right; } #div1 { position: relative; height: auto; margin: 4px; border-width: 2px; padding: 1px; } #div2a { margin: 32px; border-width: 16px; padding: 8px; } #div2b { height: 60px; margin: 32px; border-width: 16px; padding: 8px; } #div3a { position: absolute; left: 64px; top: 64px; margin: 4px; border-width: 2px; padding: 1px; } #div3b { margin: 4px; border-width: 2px; padding: 1px; } </style> </head> <body id='body'> <div id="div1"> <div id="div2a">div2a</div> <div id="div2b"> <div id="div3a">div3a</div> <div id="div3b">div3b</div> div2b </div> div1 </div> <pre id="results"></pre> <script>setTimeout(function(){ var body = document.body, bs = body.style, bCssText = bs.cssText; function setUp() { bs.cssText = bCssText; } function testBodyStatic() { info("--------------------------------------------------------------------"); info("testBodyStatic"); bs.position = "static"; writeUpTree('div1'); } function testBodyRelative() { info("testBodyRelative"); bs.position = "relative"; writeUpTree('div1'); info("--------------------------------------------------------------------"); } setUp(); testBodyStatic(); setUp(); testBodyRelative(); flushResults(); }, 100);</script> </body> </html> var result = []; var resultsEl; function info() { resultsEl = document.getElementById('results'); result[result.length] = Array.prototype.join.call(arguments,''); } function writeUpTree(id) { resultsEl = document.getElementById('results'); info('#'+id); var headers = ["tagName", "offsetLeft", "offsetTop", "offsetParent"]; var hs = []; for(var i =0; i< headers.length; i++) hs.push(headers[i], makeDots(headers[i], ' ')); info(hs.join('')); var tn = document.getElementById(id); for(var p = tn, op = p.offsetParent; op; p= p.parentNode, op=p.offsetParent) { try{ var s = p.tagName + (p.id ? "#" + p.id : ""); info( s, makeDots(s), p.offsetLeft, makeDots( String(p.offsetLeft)), p.offsetTop, makeDots(String(p.offsetTop)), op.tagName + (op.id ? "#" + op.id : "") );}catch(e){alert(e.message);} } info(''); // XXX Opera: Must pass empty string to writeln; } function makeDots( coll, ch ) { return Array.prototype.join.call({length: 14 - coll.length+1}, ch||'.'); } function flushResults() { resultsEl = document.getElementById('results'); var sResult = result.join('\r\n'); // XXX IE doesn't support whitespace with innerHTML. resultsEl.innerHTML = '\n'; // Use the Peter Michaux outerHTML hack. if(resultsEl.innerHTML !== '\n'&&'outerHTML'in resultsEl) { resultsEl.outerHTML = resultsEl.outerHTML.replace(/>[.*^<]?/, '>'+ sResult +'<'); resultsEl.innerHTML = sResult; } else { resultsEl.innerHTML = sResult; } } > Best regards > Mike Wilson > [snip example]
Received on Saturday, 15 March 2008 00:45:00 UTC