- 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