Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Find Element Position

37 views
Skip to first unread message

dhtml

unread,
Feb 17, 2008, 5:09:17 PM2/17/08
to
I've set off to the task of finding an element's position.

getOffsetCoords( el, container, coords );

container (optional) is any ancestor of el.
coords (optional) an object that has x and y properties - { x: 0, y :
0 }

I'm including scroll widths and borders of parentNodes.

This is useful for widgets like tooltip, dragdrop, context menu.

I'm throwing this up here for people to pick apart.

Areas that need improving:
* find cases where it fails
* find inefficiencies
* find things that can be improved
* formatting, or any other annoyances

Source:
http://dhtmlkitchen.com/ape/src/dom/position-f.js

testcase (I have not tested in IE6 (only 7))
http://dhtmlkitchen.com/ape/test/tests/dom/position-f-test.html

Matt Kruse

unread,
Feb 17, 2008, 5:43:23 PM2/17/08
to
On Feb 17, 4:09 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
> I've set off to the task of finding an element's position.

Were none of the 500 existing solutions sufficient? :)

Matt Kruse

Peter Michaux

unread,
Feb 17, 2008, 5:57:19 PM2/17/08
to
On Feb 17, 2:09 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
> I've set off to the task of finding an element's position.

That is a long road if you don't set some very strict limits on what
kind of elements with what kind of ancestors and what kind of doctypes/
quirksmode. Just scrolling elements in a table on a Strict page screws
up half the functions out there. Did you notice that the difference
between mouse position of an event and element position in IE are 2px
different. The "bezel" around the viewport window (i.e. the part of
the browser where the page is displayed) looks like it is about 2px.
The problem is basically a mess.

Look for posts in the archives where Matt Kruse and Richard Cornford
argue about even the idea of having a single general solution to the
position reporting problem. Matt argues it is a good idea to have a
single solution but Richard says that even if the solution could be
written it would be huge and slow. Richard seems to have explored the
oddities of this problem in great depth and has decided to have a set
of interchangeable functions/modules with the same api. Each version
suited to a different set of circumstances. This is a concept that has
interested me quite a bit recently. This is one of the main c.l.js
long term battles since I've been reading the group for a couple
years.

A good first question is why do you need to know where the element is
on the page? I have never needed to know this. For drag-drop work a
position relative to the parent element is plenty.

Peter

dhtml

unread,
Feb 17, 2008, 5:57:26 PM2/17/08
to
No, most of them make assumptions about body being an offsetParent.

Might want to check yours in Mozilla and Opera. Add some scroll left,
and scroll on body:
http://www.javascripttoolbox.com/lib/objectposition/examples.php

It fails for me in both FF 2 and Opera 9.2

And that's not even adding any border or setting position: relative on
body.

Garrett

> Matt Kruse

David Mark

unread,
Feb 17, 2008, 6:36:32 PM2/17/08
to
On Feb 17, 5:09 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
> I've set off to the task of finding an element's position.
>
> getOffsetCoords( el, container, coords );
>
> container (optional) is any ancestor of el.
> coords (optional) an object that has x and y properties - { x: 0, y :
> 0 }
>
> I'm including scroll widths and borders of parentNodes.

Watch out for Opera with regard to borders.

>
> This is useful for widgets like tooltip, dragdrop, context menu.
>
> I'm throwing this up here for people to pick apart.

I don't have time at the moment to pick it apart, but I can tell you
from experience that just getting the major browsers to work in most
cases (nobody has time to test every possible case) requires a lot of
feature testing (e.g. create a div, style it in a way known to cause
issues in some browsers, append it to the document, check various
properties against expected results, etc.) There are numerous
examples of this in my library. I can't remember if you are one of
the people who received a link to the Alpha. (?) I plan to make a
similar "pick apart" request here for the Beta version.

>
> Areas that need improving:
>  * find cases where it fails
>  * find inefficiencies
>  * find things that can be improved
>  * formatting, or any other annoyances
>
> Source:http://dhtmlkitchen.com/ape/src/dom/position-f.js
>
> testcase (I have not tested in IE6 (only 7))http://dhtmlkitchen.com/ape/test/tests/dom/position-f-test.html

If you use getBoundingClientRect when available, IE6/7 get virtually
the same results. The code to deal with the "bezel" (border of the
outermost element) issue that Peter mentioned is in my script. One
upcoming issue with that is that other browsers (e.g. the new Opera)
are starting to implement getBoundingClientRect and I wonder if they
will stay true to IE's version. IIRC, the W3C is working on a
standard for this method.

Similarly, getBoxObjectFor is very helpful with Gecko and Mozilla-
based browsers, though it has some very odd quirks related to
scrolling containers with borders.

Everything else must use the typical offsetParent loop and that is
where most of the feature test results come into play. For instance,
Opera alone includes border widths in offsetLeft/Top. Feature test
this and you don't have to worry if they change that in the future (or
other browsers start to follow their lead.) Personally, I consider
this a bug, despite the absence of a standard for the offset*
properties (the client* properties are there to measure borders.)

David Mark

unread,
Feb 17, 2008, 6:38:36 PM2/17/08
to

I've never seen one that is close, even for commonly used DOM
structures. Once you start testing cases like fixed positioned,
scrolling containers with borders in quirks mode with borders on the
body element, they completely fall apart as most rely on browser
sniffing in lieu of proper feature testing.

David Mark

unread,
Feb 17, 2008, 6:42:17 PM2/17/08
to

Yes, that solution completely ignores border issues.

A relatively positioned body element? Now there's an odd test case.
Never thought to try that one, but I don't think it would be an issue
with mine (relative positioning works fine for other elements.)

From looking at one of your recently posted examples, I suspect I need
to add a couple of additional feature tests related to tables, but
they should only affect agents that implement neither
getBoundingClientRect or getBoxObjectFor.

David Mark

unread,
Feb 17, 2008, 6:53:09 PM2/17/08
to
On Feb 17, 5:57 pm, Peter Michaux <petermich...@gmail.com> wrote:
> On Feb 17, 2:09 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
>
> > I've set off to the task of finding an element's position.
>
> That is a long road if you don't set some very strict limits on what
> kind of elements with what kind of ancestors and what kind of doctypes/
> quirksmode. Just scrolling elements in a table on a Strict page screws
> up half the functions out there. Did you notice that the difference

Then those aren't really solutions at all.

> between mouse position of an event and element position in IE are 2px
> different. The "bezel" around the viewport window (i.e. the part of
> the browser where the page is displayed) looks like it is about 2px.

See my code, specifically the getBoundingClientRect branch.

> The problem is basically a mess.

No question.

>
> Look for posts in the archives where Matt Kruse and Richard Cornford
> argue about even the idea of having a single general solution to the
> position reporting problem. Matt argues it is a good idea to have a
> single solution but Richard says that even if the solution could be
> written it would be huge and slow. Richard seems to have explored the
> oddities of this problem in great depth and has decided to have a set
> of interchangeable functions/modules with the same api. Each version
> suited to a different set of circumstances. This is a concept that has
> interested me quite a bit recently. This is one of the main c.l.js
> long term battles since I've been reading the group for a couple
> years.
>
> A good first question is why do you need to know where the element is
> on the page? I have never needed to know this. For drag-drop work a
> position relative to the parent element is plenty.

Not if you want to drag or position elements over a statically
positioned element. This is covered in the unit tests for my drag and
drop module. The test involving a statically positioned element is
not included unless the offset module is present. Same for the drop
target test. You could handle drop targets without calculating
offsets if the dragged element and target share the same positioned
parent, but that isn't possible for all applications. Also, some of
the quirks discussed here (e.g. borders in Opera) come into play for
statically positioned targets, whether an offset from the document
origin is needed or not.

dhtml

unread,
Feb 17, 2008, 6:57:07 PM2/17/08
to
On Feb 17, 3:36 pm, David Mark <dmark.cins...@gmail.com> wrote:
> On Feb 17, 5:09 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
>

> Watch out for Opera with regard to borders.
>

Covered.

>
>
> > This is useful for widgets like tooltip, dragdrop, context menu.
>
> > I'm throwing this up here for people to pick apart.
>
> I don't have time at the moment to pick it apart, but I can tell you
> from experience that just getting the major browsers to work in most
> cases (nobody has time to test every possible case) requires a lot of
> feature testing (e.g. create a div, style it in a way known to cause
> issues in some browsers, append it to the document, check various
> properties against expected results, etc.) There are numerous
> examples of this in my library. I can't remember if you are one of
> the people who received a link to the Alpha. (?) I plan to make a
> similar "pick apart" request here for the Beta version.
>

I'd like to see that.

>
> If you use getBoundingClientRect when available, IE6/7 get virtually
> the same results. The code to deal with the "bezel" (border of the
> outermost element) issue that Peter mentioned is in my script. One
> upcoming issue with that is that other browsers (e.g. the new Opera)
> are starting to implement getBoundingClientRect and I wonder if they
> will stay true to IE's version. IIRC, the W3C is working on a
> standard for this method.
>

Anne van Kesteren started CSSOM view module two years ago.
http://dev.w3.org/cvsweb/csswg/cssom-view/Overview.html?rev=1.2#offset-attributes

The document is mostly inaccurate. I've emailed him about this (and
his other inaccurate docs), but he is unable or unwilling to change.

> Similarly, getBoxObjectFor is very helpful with Gecko and Mozilla-
> based browsers, though it has some very odd quirks related to
> scrolling containers with borders.
>

https://bugzilla.mozilla.org/show_bug.cgi?id=340571

I'm going to look into getBoxObjectFor. If it's not buggy, it could be
a conditional:

else if(el.getBoxObjectFor) {

}

It might shoujld make it simpler and more efficient. I will
investigate.

> Everything else must use the typical offsetParent loop and that is
> where most of the feature test results come into play. For instance,
> Opera alone includes border widths in offsetLeft/Top. Feature test
> this and you don't have to worry if they change that in the future (or
> other browsers start to follow their lead.)

Yes, I have a load time constants in a closure. I do the feature
testing style you described in your prev paragarph.

Personally, I consider
> this a bug, despite the absence of a standard for the offset*
> properties (the client* properties are there to measure borders.)

It is as per Anne's spec. You should post on the css mailing list:
"www-...@w3.org" <www-...@w3.org>

dhtml

unread,
Feb 17, 2008, 7:06:43 PM2/17/08
to
On Feb 17, 2:57 pm, Peter Michaux <petermich...@gmail.com> wrote:
> On Feb 17, 2:09 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
>
> > I've set off to the task of finding an element's position.
>
> That is a long road if you don't set some very strict limits on what
> kind of elements with what kind of ancestors and what kind of doctypes/
> quirksmode. Just scrolling elements in a table on a Strict page screws
> up half the functions out there.
Can you provide some HTML testcase?

<table>
<caption>blah</caption>
<tbody>
<tr>
<td>

</td>
</tr>
</tbody>
</table>

Did you notice that the difference
> between mouse position of an event and element position in IE are 2px
> different. The "bezel" around the viewport window (i.e. the part of
> the browser where the page is displayed) looks like it is about 2px.
> The problem is basically a mess.
>

An element position from the viewport is offset by that border in IE.

This goes back to the difference between IE and Mozilla. IE calls HTML
the ICB, Moz treats viewport the ICB. IE in backcompat mode treats
BODY as the ICB. This is the big problem area.

> Look for posts in the archives where Matt Kruse and Richard Cornford
> argue about even the idea of having a single general solution to the
> position reporting problem. Matt argues it is a good idea to have a
> single solution but Richard says that even if the solution could be
> written it would be huge and slow. Richard seems to have explored the
> oddities of this problem in great depth and has decided to have a set
> of interchangeable functions/modules with the same api. Each version
> suited to a different set of circumstances. This is a concept that has
> interested me quite a bit recently. This is one of the main c.l.js
> long term battles since I've been reading the group for a couple
> years.
>

I will search that.

> A good first question is why do you need to know where the element is
> on the page? I have never needed to know this. For drag-drop work a
> position relative to the parent element is plenty.
>

For drag drop, I might have two different containers.

For a tooltip or context menu or panel, I might have any containers
surrounding the actuator/target.

Thank you,

Garrett

> Peter

Peter Michaux

unread,
Feb 17, 2008, 7:17:22 PM2/17/08
to
On Feb 17, 4:06 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
> On Feb 17, 2:57 pm, Peter Michaux <petermich...@gmail.com> wrote:> On Feb 17, 2:09 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
>
> > > I've set off to the task of finding an element's position.
>
> > That is a long road if you don't set some very strict limits on what
> > kind of elements with what kind of ancestors and what kind of doctypes/
> > quirksmode. Just scrolling elements in a table on a Strict page screws
> > up half the functions out there.
>
> Can you provide some HTML testcase?

I don't know where they are. Just start mixing nested scrolling divs
in scrolling divs, tables in tables and combinations of the two. It
won't take more than one try to find problems.

[snip]

> > A good first question is why do you need to know where the element is
> > on the page? I have never needed to know this. For drag-drop work a
> > position relative to the parent element is plenty.
>
> For drag drop, I might have two different containers.

There are many ways to do it so the positioning problem is quite easy.
The wrong way to do it is depend on some complex, expensive function
that calculates the position of the element relative to the page top
left.

> For a tooltip or context menu or panel, I might have any containers
> surrounding the actuator/target.

You don't need to know the position of what was clicked for a tooltip,
context menu etc. You just need to know the position of the mouse
event. That is much easier. Have a look in the FAQ notes about browser
detection and the scroll reporting function.

Every case I've encountered there is just an easier way to do it than
use absolute position reporting. I'm sure there are cases where it is
necessary but I bet they are rare.

Peter

David Mark

unread,
Feb 17, 2008, 7:43:25 PM2/17/08
to
On Feb 17, 6:57 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
> On Feb 17, 3:36 pm, David Mark <dmark.cins...@gmail.com> wrote:
>
> > On Feb 17, 5:09 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
>
> > Watch out for Opera with regard to borders.
>
> Covered.
>
>
>
>
>
>
>
> > > This is useful for widgets like tooltip, dragdrop, context menu.
>
> > > I'm throwing this up here for people to pick apart.
>
> > I don't have time at the moment to pick it apart, but I can tell you
> > from experience that just getting the major browsers to work in most
> > cases (nobody has time to test every possible case) requires a lot of
> > feature testing (e.g. create a div, style it in a way known to cause
> > issues in some browsers, append it to the document, check various
> > properties against expected results, etc.)  There are numerous
> > examples of this in my library.  I can't remember if you are one of
> > the people who received a link to the Alpha. (?)  I plan to make a
> > similar "pick apart" request here for the Beta version.
>
> I'd like to see that.

Check your email. I sent you a link to the Alpha.

>
>
>
> > If you use getBoundingClientRect when available, IE6/7 get virtually
> > the same results.  The code to deal with the "bezel" (border of the
> > outermost element) issue that Peter mentioned is in my script.  One
> > upcoming issue with that is that other browsers (e.g. the new Opera)
> > are starting to implement getBoundingClientRect and I wonder if they
> > will stay true to IE's version.  IIRC, the W3C is working on a
> > standard for this method.
>

> Anne van Kesteren started CSSOM view module two years ago.http://dev.w3.org/cvsweb/csswg/cssom-view/Overview.html?rev=1.2#offse...


>
> The document is mostly inaccurate. I've emailed him about this (and

I looked it over recently and did notice some odd choices.

> his other inaccurate docs), but he is unable or unwilling to change.

Oh well.

>
> > Similarly, getBoxObjectFor is very helpful with Gecko and Mozilla-
> > based browsers, though it has some very odd quirks related to
> > scrolling containers with borders.
>
> https://bugzilla.mozilla.org/show_bug.cgi?id=340571
>
> I'm going to look into getBoxObjectFor. If it's not buggy, it could be
> a conditional:

It has a few quirks, but all-in-all, it is far superior to the manual
offsetParent iteration.

>
> else if(el.getBoxObjectFor) {
>
> }

Use isHostMethod! Feature testing by boolean type conversion is out.

>
> It might shoujld make it simpler and more efficient. I will
> investigate.

It is far simpler and far more efficient. It doesn't account for
scrolling containers though, so you still have to manually iterate
through those. IIRC, it also needs a little help to return meaningful
results for fixed position elements.

>
> > Everything else must use the typical offsetParent loop and that is
> > where most of the feature test results come into play.  For instance,
> > Opera alone includes border widths in offsetLeft/Top.  Feature test
> > this and you don't have to worry if they change that in the future (or
> > other browsers start to follow their lead.)
>
> Yes, I have a load time constants in a closure. I do the feature
> testing style you described in your prev paragarph.
>
>   Personally, I consider
>
> > this a bug, despite the absence of a standard for the offset*
> > properties (the client* properties are there to measure borders.)
>
> It is as per Anne's spec. You should post on the css mailing list:

> "www-st...@w3.org" <www-st...@w3.org>

No time for another forum right now. I will probably just let the w3c
sort it out.

Matt Kruse

unread,
Feb 17, 2008, 8:52:23 PM2/17/08
to

That's an interesting test case, but probably one that would never
occur in a real-world situation.
If a proposed "solution" fails this case, I'm not sure anyone would
actually care.
And if someone does have such a situation on their hand, they probably
already realize that no generalized solution is going to work for
them.

As long as the proposed solution makes it clear what cases are and are
not covered, I think it's okay to not "solve" them all.

Matt Kruse

David Mark

unread,
Feb 17, 2008, 9:29:06 PM2/17/08
to
On Feb 17, 8:52 pm, Matt Kruse <m...@mattkruse.com> wrote:
> On Feb 17, 5:38 pm, David Mark <dmark.cins...@gmail.com> wrote:
>
> > On Feb 17, 5:43 pm, Matt Kruse <m...@mattkruse.com> wrote:
> > > Were none of the 500 existing solutions sufficient? :)
> > I've never seen one that is close, even for commonly used DOM
> > structures.  Once you start testing cases like fixed positioned,
> > scrolling containers with borders in quirks mode with borders on the
> > body element, they completely fall apart as most rely on browser
> > sniffing in lieu of proper feature testing.
>
> That's an interesting test case, but probably one that would never
> occur in a real-world situation.

It does on my test page. Along with several other ridiculous
scenarios. I didn't add these cases because I thought somebody would
actually use them, but to expose as many quirks as possible.

> If a proposed "solution" fails this case, I'm not sure anyone would
> actually care.

Perhaps not.

> And if someone does have such a situation on their hand, they probably
> already realize that no generalized solution is going to work for
> them.

The described test case works for me. I suspect that by making sure
it worked, I avoided other related quirks.

>
> As long as the proposed solution makes it clear what cases are and are
> not covered, I think it's okay to not "solve" them all.
>

It is virtually impossible to list every possible case that is not
covered. One can only list cases that are known (or thought) to be
covered and which user agents (and layout modes) were used to test
them.

The last time I put my offset location function through a battery of
tests, I limited the agents involved to:

IE5/6/7
Windows Safari (Beta of course, so things could have changed since)
Opera 9
Firefox 2
Netscape 6.2
And whatever the last version of Netscape was (seemed to mirror
Firefox in both standards and quirks mode.)

By the time I was done, I couldn't come up with any test cases that
failed (meaning one or more pixels off) in standards or quirks mode,
regardless of margins or borders on the outermost element. Granted, I
am sure that there were some cases I failed to consider. IIRC,
scrolling tables weren't considered at all, which means I probably
need at least one additional feature test. And who can say what Mac
IE (or even Safari) would do? When I release the public Beta, I hope
somebody will give me feedback on those.

The end result wasn't particularly bloated or slow, but all things
relative, it was more than most apps would need. I really need to
make some portions of that module optional.

Jeff

unread,
Feb 17, 2008, 9:39:45 PM2/17/08
to

Well, where does that leave us? I've been using a while offsetParent
loop and that's pretty close for my uses, but if there is something
closer that isn't a glut of code, I'd like to see it. Scrollable
containers aren't an issue for me.

Jeff
>
> Matt Kruse

David Mark

unread,
Feb 17, 2008, 9:55:57 PM2/17/08
to

Depending on what you use it for, "pretty close" may suffice.
However, for example, if you wish to transition a random element by
progressively rendering a clone on top of it, a single pixel off can
seriously degrade the result.

> closer that isn't a glut of code, I'd like to see it. Scrollable
> containers aren't an issue for me.

Perhaps you should start by looking at Garrett's sample. I imagine it
has a way to short-circuit the logic dealing with scrolling containers
(a must as such logic is a major performance hit.)

Jeff

unread,
Feb 17, 2008, 11:41:49 PM2/17/08
to

I never even thought of that! Usually I'm just menuing.


>
>> closer that isn't a glut of code, I'd like to see it. Scrollable
>> containers aren't an issue for me.
>
> Perhaps you should start by looking at Garrett's sample.

Perhaps I'm a little too tired but I don't remember seeing it. Do you
have a pointer for it?

Jeff

dhtml

unread,
Feb 17, 2008, 11:48:18 PM2/17/08
to
On Feb 17, 5:52 pm, Matt Kruse <m...@mattkruse.com> wrote:
> On Feb 17, 5:38 pm, David Mark <dmark.cins...@gmail.com> wrote:
>
> > On Feb 17, 5:43 pm, Matt Kruse <m...@mattkruse.com> wrote:
> > > Were none of the 500 existing solutions sufficient? :)
> > I've never seen one that is close, even for commonly used DOM
> > structures. Once you start testing cases like fixed positioned,
> > scrolling containers with borders in quirks mode with borders on the
> > body element, they completely fall apart as most rely on browser
> > sniffing in lieu of proper feature testing.
>
> That's an interesting test case,

That's not a test case.

but probably one that would never
> occur in a real-world situation.
> If a proposed "solution" fails this case, I'm not sure anyone would
> actually care.

Anyone who's used:

body {
position: relative;
}

to force a containing block,

or
#area {
overflow: scroll;
}

would probably care.


> And if someone does have such a situation on their hand, they probably
> already realize that no generalized solution is going to work for
> them.
>

Your example addresses the scroll case.

> As long as the proposed solution makes it clear what cases are and are
> not covered, I think it's okay to not "solve" them all.
>

That's true. Having position: relative and border on body aren't too
far out though.

The difficulty with body is that the CSSOM spec says taht the
offsetParent algorithm stops at body. That contradicts what we know
about offsetParent or containing blocks. It's a quirks mode behavior
in a spec.

> Matt Kruse

David Mark

unread,
Feb 18, 2008, 12:01:37 AM2/18/08
to
On Feb 17, 5:09 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
> I've set off to the task of finding an element's position.
>
> getOffsetCoords( el, container, coords );
>
> container (optional) is any ancestor of el.
> coords (optional) an object that has x and y properties - { x: 0, y :
> 0 }
>
> I'm including scroll widths and borders of parentNodes.
>
> This is useful for widgets like tooltip, dragdrop, context menu.

You shouldn't need it for a context menu.


>
> I'm throwing this up here for people to pick apart.
>
> Areas that need improving:
>  * find cases where it fails
>  * find inefficiencies
>  * find things that can be improved
>  * formatting, or any other annoyances
>
> Source:http://dhtmlkitchen.com/ape/src/dom/position-f.js
>
> testcase (I have not tested in IE6 (only 7))http://dhtmlkitchen.com/ape/test/tests/dom/position-f-test.html

I took a little time to survey this.

// Load-time constants.
var IS_BACK_COMPAT = document.compatMode === "BackCompat";

You can't rely on this flag in IE < 6.


// IE, Safari, and Opera support clientTop. FF 2 doesn't
var IS_CLIENT_TOP_SUPPORTED = 'clientTop'in document.documentElement;

I use a wrapper that uses border styles in lieu of clientLeft/Top. I
think it makes the code easier to follow.

// XXX Opera <= 9.2 - parent border widths are included in offsetTop.
var IS_PARENT_BORDER_INCLUDED_IN_OFFSET;

Can I assume from the comment that this flag will be false in the new
Opera? It doesn't really matter, but it would be good if they changed
their scheme to match other browsers.

// XXX Opera <= 9.2 - body offsetTop is inherited to children's
offsetTop
// when body position is not static.
var IS_BODY_OFFSET_INHERITED;

A positioned body element is a case I didn't consider. I am not
surprised that such a style causes issues.

// XXX Mozilla includes a table border in the TD's offsetLeft.
// There is 1 exception:
// When the TR has position: relative and the TD has block level
content.
// In that case, the TD does not include the TABLE's border in it's
offsetLeft.
// We do not account for this peculiar bug.
var IS_TABLE_BORDER_INCLUDED_IN_TD_OFFSET;

So is this variable a placeholder?

var
IS_STATIC_BODY_OFFSET_PARENT_BUT_ABSOLUTE_CHILD_SUBTRACTS_BODY_BORDER_WIDTH
= false;

Borders/margins on the HTML element (in standards mode) cause
additional aggravations.

var getComputedStyle = window.getComputedStyle;
var bcs;

var positionedExp = /^(?:r|a|f)/,
absoluteExp = /^(?:a|f)/;

There are several issues that are unique to fixed positioning. For
one, fixed elements in Opera 9 have a null offsetParent. In this
case, I resorted to getComputedStyle.

/**
* @param {HTMLElement} el you want coords of.
* @param {HTMLElement} container to look up to.
* @param {x:{Number}, y:{Number}} coords object to pass in.
* @param {boolean} forceRecalc if true, forces recalculation of body
scroll offsets.

This is an interesting idea. Is it to make things less painful for
applications that don't scroll?

* @return {x:{Number}, y:{Number}} coords of el from container.
*
* Passing in a container will improve performance in other browsers,
* but will punish IE with a recursive call. Test accordingly.

Same for Firefox if you use getBoxObjectFor. For some reason, I
didn't do this in the getBoundingClientRect branch, but resorted to
the offsetParent loop. IIRC, IE6/7 had the fewest issues with that
method, though I should change it to work like the gBOF branch for
performance reasons.

* <p>
* Container is sometimes irrelevant. Container is irrelevant when
comparing two objects'
* positions against one another, to see if they intersect. In this
case, pass in document.

It can be relevant if the two elements share a common positioned
parent. And why not default to document?

* </p>
* Passing in re-used coords will greatly improve performance in all
browsers.

Can you elaborate on re-used coords?

* There is a side effect to passing in coords:
* For animation or drag drop operations, reuse coords.
*/

I don't follow that. And I can't conceive of an animation that would/
should be concerned with offset positions.

function getOffsetCoords(el, container, coords) {

var doc = document, body = doc.body, documentElement =
doc.documentElement;

Apparently this function is good for one document. I think it is a
good idea to allow for multiple documents in functions like these
(e.g. for iframes, objects, etc.)

if(!container)
container = doc;

if(!coords)
coords = {x:0, y:0};

if(el === container) {
coords.x = coords.y = 0;
return coords;
}
if("getBoundingClientRect"in el) {

I would avoid the in operator for compatibility reasons.


// In BackCompat mode, body's border goes to the window. BODY is
ICB.
var rootBorderEl = (IS_BACK_COMPAT ? body : documentElement);

But this flag isn't correct in IE < 6 and those versions do not
display the documentElement. IIRC, this is okay in this case as I
think IE5.x considers the viewport border to be part of the (otherwise
invisible) HTML element.

var box = el.getBoundingClientRect();
var x, y;
x = box.left - rootBorderEl.clientLeft
+ Math.max( documentElement.scrollLeft, body.scrollLeft );
y = box.top - rootBorderEl.clientTop
+ Math.max( documentElement.scrollTop, body.scrollTop );
if(container !== doc) {
box = getOffsetCoords(container, null);
x -= box.x;
y -= box.y;
}
if(IS_BACK_COMPAT) {
var curSty = body.currentStyle;

Object inference based on getBoundingClientRect (will break in the new
Opera.)

x += parseInt(curSty.marginLeft);
y += parseInt(curSty.marginTop);

Use parseFloat. Oddly enough, my gBCR branch does not consider
margins at all and I am pretty sure I tested quirks mode w/ body
margins in IE6/7. I'll have to re-test that. Of course, I need to re-
test everything now that I have transplanted the code into a new
library (I'm really looking forward to *that*.)

}
coords.x = x;
coords.y = y;

return coords;
}

// Crawling up the tree.
else {

var offsetLeft = el.offsetLeft,
offsetTop = el.offsetTop,
isBodyStatic = !positionedExp.test(bcs.position);

What if bcs does not exist. You should allow applications that need
to run in ancient browsers to compensate by setting inline styles
(i.e. check inline styles as a fallback.)

[snip]

----
// Loop up, gathering scroll offsets on parentNodes.
// when we get to a parent that's an offsetParent, update
// the current offsetParent marker.

I prefer to loop through offsetParents and then deal with scrolling
parents as an optional afterthought. This makes it easy for
applications that do not involve scrolling containers to prevent the
extra work. Also, the adjustments for scrolling containers are needed
for the gBOF branch.

for( var parent = el.parentNode; parent && parent !== container;
parent = parent.parentNode) {
if(parent !== body && parent !== documentElement) {
lastOffsetParent = parent;
offsetLeft -= parent.scrollLeft;
offsetTop -= parent.scrollTop;
}
if(parent === offsetParent) {
// If we get to BODY and have static position, skip it.
if(parent === body && isBodyStatic);
else {

// XXX Mozilla; Exclude static body; if static, it's offsetTop
will be wrong.

Negative in some cases, IIRC.
// Include parent border widths. This matches behavior of
clientRect approach.
// XXX Opera <= 9.2 includes parent border widths.
// See IS_PARENT_BORDER_INCLUDED_IN_OFFSET below.
if( !IS_PARENT_BORDER_INCLUDED_IN_OFFSET &&
! (parent.tagName === "TABLE" &&
IS_TABLE_BORDER_INCLUDED_IN_TD_OFFSET)) {

You don't need a strict comparison there.

if( IS_CLIENT_TOP_SUPPORTED ) {
offsetLeft += parent.clientLeft;
offsetTop += parent.clientTop;
}
else {
var pcs = getComputedStyle(parent, "");
// Mozilla doesn't support clientTop. Add borderWidth to the
sum.
offsetLeft += parseInt(pcs.borderLeftWidth)||0;
offsetTop += parseInt(pcs.borderTopWidth)||0;

As mentioned, allow for inline styles.
}
}
if(parent !== body) {
offsetLeft += offsetParent.offsetLeft;
offsetTop += offsetParent.offsetTop;
offsetParent = parent.offsetParent; // next marker to check
for offsetParent.
}
}
}
}
[snip]
var bodyOffsetLeft = parseInt(bcs.marginLeft)||0;
var bodyOffsetTop = parseInt(bcs.marginTop)||0;
}

Use parseFloat or em-based layout (for example) will have rounding
errors.

if(isBodyStatic) {

// XXX: Safari will use HTML for containing block (CSS),
// but will subtract the body's border from the body's absolutely
positioned
// child.offsetTop. Safari reports the child's offsetParent is
BODY, but
// doesn't treat it that way (Safari bug).
if(!isLastElementAbsolute) {
if(false == IS_PARENT_BORDER_INCLUDED_IN_OFFSET

Shouldn't this be !IS_PARENT_BORDER_INCLUDED_IN_OFFSET?

&& (container === document || container === documentElement)){
offsetTop += parseInt(bcs.borderTopWidth);
offsetLeft += parseInt(bcs.borderLeftWidth);


Use parseFloat.

}
}
else {
// XXX Safari subtracts border width of body from element's
offsetTop (opera does it, too)

I definitely remember this one.


if(IS_STATIC_BODY_OFFSET_PARENT_BUT_ABSOLUTE_CHILD_SUBTRACTS_BODY_BORDER_WIDTH)
{
offsetTop += parseInt(bcs.borderTopWidth);
offsetLeft += parseInt(bcs.borderLeftWidth);

Same here (parseFloat.)

}
}
}
else if(container === doc || container === documentElement) {
// If the body is positioned, add its left and top value.

// Safari will sometimes return "auto" for computedStyle, which
results NaN.


So will IE for statically positioned elements. Opera will return
incorrect results for those with borders.

bodyOffsetLeft += parseInt(bcs.left)||0;
bodyOffsetTop += parseInt(bcs.top)||0;


Use parseFloat.

// XXX: Opera normally include the parentBorder in offsetTop.
// We have a preventative measure in the loop above.
if(isLastElementAbsolute) {
if(IS_CLIENT_TOP_SUPPORTED &&
IS_PARENT_BORDER_INCLUDED_IN_OFFSET) {
offsetTop += body.clientTop;
offsetLeft += body.clientLeft;
}
}
}
}

coords.x = offsetLeft + bodyOffsetLeft;
coords.y = offsetTop + bodyOffsetTop;

return coords;
}
}

// A closure for initializing load time constants.
if(!("getBoundingClientRect"in document.documentElement))

As mentioned, I would avoid the in operator.

(function(){
var waitForBodyTimer = setInterval(function
domInitLoadTimeConstants() {

What is this about? A DOM ready simulation?

if(!document.body) return;

This excludes XHTML documents in Windows Safari and (reportedly) some
older Gecko-based browsers.


clearInterval(waitForBodyTimer);
var body = document.body;
var s = body.style, padding = s.padding, border = s.border,
position = s.position, marginTop = s.marginTop;
s.padding = 0;
s.top = 0;
s.border = '1px solid transparent';

var x = document.createElement('div');
x.id='asdf';

Why do you need to assign an ID?

var xs = x.style;
xs.margin = 0;
xs.position = "static";

x = body.appendChild(x);

This will cause a twitch during page load. I would make the height
and width 0 if you can get away with it in this test.

IS_PARENT_BORDER_INCLUDED_IN_OFFSET = (x.offsetTop === 1);

s.border = 0;
s.padding = 0;

var table = document.createElement('table');
try {
table.innerHTML = "<tbody><tr><td>bla</td></tr></tbody>";

Why not use DOM methods and lose the try-catch?

table.style.border = "17px solid red";

Why set border colors on these dummy elements?


table.cellSpacing = table.cellPadding = 0;

body.appendChild(table);
IS_TABLE_BORDER_INCLUDED_IN_TD_OFFSET =
table.getElementsByTagName("td")[0].offsetLeft === 17;

body.removeChild(table);
} catch(ex){/*IE, we don't care*/}
if(getComputedStyle) {
bcs = getComputedStyle(document.body,'');
}
// Now add margin to determine if body offsetTop is inherited.
s.marginTop = "1px";
s.position = "relative";
IS_BODY_OFFSET_INHERITED = (x.offsetTop === 1);

s.marginTop = "0";

xs.position = "absolute";
s.position = "static";
if(x.offsetParent === body) {
s.border = "1px solid #f3f3f3";
xs.top = "2px";
// XXX Safari gets offsetParent wrong (says 'body' when body is
static,
// but then positions element from ICB and then subtracts body's
clientWidth.
// Safari is half wrong.
//
// XXX Mozilla says body is offsetParent but does NOT subtract
BODY's offsetWidth.

Subtracts BODY's clientWidth?

// Mozilla is completely wrong.

IS_STATIC_BODY_OFFSET_PARENT_BUT_ABSOLUTE_CHILD_SUBTRACTS_BODY_BORDER_WIDTH
= x.offsetTop === 1;
}
s.position = position;

s.marginTop = marginTop;
// Put back border and padding the way they were.
s.border = border;
s.padding = padding;

This is going to be twitchy.


// Release memory (IE).
body = s = x = xs = table = null;

}, 60);
})();

/**
* @return {boolean} true if a is vertically within b's content area
(and does not overlap, top nor bottom).
*/
function isInsideElement(a, b) {
var aTop = getOffsetCoords(a).y;
var bTop = getOffsetCoords(b).y;
return aTop + a.offsetHeight <= bTop + b.offsetHeight && aTop >=
bTop;
}

/**
* @return {boolean} true if a overlaps the top of b's content area.
*/
function isAboveElement(a, b) {
return (getOffsetCoords(a).y <= getOffsetCoords(b).y);
}

/**
* @return {boolean} true if a overlaps the bottom of b's content
area.
*/
function isBelowElement(a, b) {
return (getOffsetCoords(a).y + a.offsetHeight >=
getOffsetCoords(b).y + b.offsetHeight);
}

[snip]

The rest appears unrelated.

Sorry for the inevitable wrapping. I didn't have time to make this
newsreader-friendly.

BTW, the email I sent to you bounced (and I was replying to one of
your messages.) Perhaps GMail is on the fritz tonight?

dhtml

unread,
Feb 18, 2008, 8:05:33 PM2/18/08
to
On Feb 17, 9:01 pm, David Mark <dmark.cins...@gmail.com> wrote:


On Feb 17, 9:01 pm, David Mark <dmark.cins...@gmail.com> wrote:
> On Feb 17, 5:09 pm, dhtml <dhtmlkitc...@gmail.com> wrote:

> I took a little time to survey this.
>

It's an excellent review. Questions about comments/x.d/borderColor, I
just corrected the mistakes and
snipped the question to keep focused on other things.


> var IS_BACK_COMPAT = document.compatMode === "BackCompat";
>
> You can't rely on this flag in IE < 6.
>

What do you do? There's likely to eventually be a browser that
supports getBoundingClientRect, yet has document.compatMode ==
"undefined"

<snip>

> I use a wrapper that uses border styles in lieu of clientLeft/Top. I
> think it makes the code easier to follow.
>

That would be easier to follow; it would reduce conditional checks and
put the logic on one place. I was doing this at first, but it was
slow. I replaced it with inline code and the time
was cut almost in half.

Removing the extra function call made a big difference.

> // XXX Opera <= 9.2 - parent border widths are included in offsetTop.
> var IS_PARENT_BORDER_INCLUDED_IN_OFFSET;
>
> Can I assume from the comment that this flag will be false in the new
> Opera? It doesn't really matter, but it would be good if they changed
> their scheme to match other browsers.
>

The flag gets set based on a test:

// A closure for initializing load time constants.
if(!("getBoundingClientRect"in document.documentElement))

(function(){
var waitForBodyTimer = setInterval(function
domInitLoadTimeConstants() {

if(!document.body) return;

clearInterval(waitForBodyTimer);

var x = document.createElement('div');

var xs = x.style;
xs.margin = 0;
xs.position = "static";
x = body.appendChild(x);

IS_PARENT_BORDER_INCLUDED_IN_OFFSET = (x.offsetTop === 1);

...
}, 60);
})();


<snip>

> A positioned body element is a case I didn't consider. I am not
> surprised that such a style causes issues.
>

It is a very real case. Setting position: relative makes an element a
containing block for absolutely positioned elements.

For example:

#adiv {
position: absolute;
top: 0;
}
body {
margin: 10px;
}

adiv's containing block is HTML. It's offsetParent should be HTML, and
in IE, it is.

In Opera, Safari, Firefox the offsetParent is BODY. This is per Anne
van Kesteren's spec.

In Safari, the offsetTop of adiv will be -10. Given the fact that
adiv's offsetParent is BODY, this makes sense.


> var
> IS_STATIC_BODY_OFFSET_PARENT_BUT_ABSOLUTE_CHILD_SUBTRACTS_BODY_BORDER_WIDTH
> = false;
>
> Borders/margins on the HTML element (in standards mode) cause
> additional aggravations.
>
> var getComputedStyle = window.getComputedStyle;
> var bcs;
>
> var positionedExp = /^(?:r|a|f)/,
> absoluteExp = /^(?:a|f)/;
>
> There are several issues that are unique to fixed positioning. For
> one, fixed elements in Opera 9 have a null offsetParent. In this
> case, I resorted to getComputedStyle.
>

That would go along with Anne's spec. In the case of fixed
positioning, I haven't addressed yet.

myFixedDiv.offsetTop
myFixedDiv.offsetLeft

Would seem to provide the desired result.

> * @param {boolean} forceRecalc if true, forces recalculation of body
> scroll offsets.
>
> This is an interesting idea. Is it to make things less painful for
> applications that don't scroll?
>

It was an idea for addressing the issue where body's border/margin/
padding/top/left are unchanging.

It was impossible/extremely difficult to test, and so I removed that.

> Same for Firefox if you use getBoxObjectFor. For some reason, I
> didn't do this in the getBoundingClientRect branch, but resorted to
> the offsetParent loop. IIRC, IE6/7 had the fewest issues with that
> method, though I should change it to work like the gBOF branch for
> performance reasons.
>

getBoxObjectFor is being discouraged in a bugzilla:
https://bugzilla.mozilla.org/show_bug.cgi?id=340571

It's not supported for HTML. It's not guaranteed to provide any
results in HTML documents.

<snip>

>
> Can you elaborate on re-used coords?
>

If you call getOffsetCoords(el, cont),

it creates an object {x: 0, y: 0};

if you pass in an object
getBoxOffsetCoords(el. cont, this.coords);

It doesn't create a new object. For drag operations, it could mean
creating hundreds of objects.

//update coords, no need to return anything.
getOffsetCoords(dropTarget.el, document, dropTarget.coords);


> function getOffsetCoords(el, container, coords) {
>
> var doc = document, body = doc.body, documentElement =
> doc.documentElement;
>
> Apparently this function is good for one document. I think it is a
> good idea to allow for multiple documents in functions like these
> (e.g. for iframes, objects, etc.)
>

I am too lazy to write a frame-based test. It might work. I guess it
wouldn't hurt to put in:

doc = el.ownerDocument.


> if("getBoundingClientRect"in el) {
>
> I would avoid the in operator for compatibility reasons.
>

What copatibility reasons?


> // In BackCompat mode, body's border goes to the window. BODY is
> ICB.
> var rootBorderEl = (IS_BACK_COMPAT ? body : documentElement);
>
> But this flag isn't correct in IE < 6 and those versions do not
> display the documentElement. IIRC, this is okay in this case as I
> think IE5.x considers the viewport border to be part of the (otherwise
> invisible) HTML element.
>

I don't know how to address this. I don't even have IE6, much less IE
5.5 to test on.


> var box = el.getBoundingClientRect();
> var x, y;
> x = box.left - rootBorderEl.clientLeft
> + Math.max( documentElement.scrollLeft, body.scrollLeft );
> y = box.top - rootBorderEl.clientTop
> + Math.max( documentElement.scrollTop, body.scrollTop );
> if(container !== doc) {
> box = getOffsetCoords(container, null);
> x -= box.x;
> y -= box.y;
> }
> if(IS_BACK_COMPAT) {
> var curSty = body.currentStyle;
>
> Object inference based on getBoundingClientRect (will break in the new
> Opera.)

That's true, it is object inference. The code assumes:
if documet.getBoundingClientRect, then body.currentStyle is supported.
Coincidentally Opera supports currentStyle. It is very likely that
this
will break in future versions of FF/Safari.

Changed to:
if(IS_BACK_COMPAT && IS_CURRENT_STYLE_SUPPORTED) {


>
> x += parseInt(curSty.marginLeft);
> y += parseInt(curSty.marginTop);
>
> Use parseFloat.

Am I missing a fraction of a pixel? I think the coords returned should
be integers. I can't remember, but I think I remember IE having
problems with style values with floating point numbers.


Using parseInt and parseFloat:

Opera 9.2: (same result for both)
Expected: 2750 Actual:1794

Safari - parseFloat
2750 Actual:2748

Safari - parseInt
Expected: 2750 Actual:2748

Mozilla - parseFloat:
Expected: 2750 Actual:2750.734
Mozilla - parseInt:
Expected: 2750 Actual:2749

IE - (IE does not get here)
PASS testGetOffsetLeftFloatingPointEM: passed.

Opera was way off. Forget about accuracy when dealing with EMs in
Opera.

All browsers fail when using EM. Mozilla would be the closest because
it keeps floating pixels.

Using Math.round and parseFloat now, I can expect the number to be
correct in Mozilla. Obviously not good for performance. I will go
through later and try to profile it. I want to hook a profiler into
the test runner.

> I need to re-
> test everything now that I have transplanted the code into a new
> library (I'm really looking forward to *that*.)
>

I use a patched version of the YUI test runner. I think it's less
painful than using JSUnit. I can help you get started with this if you
want.


>
> What if bcs does not exist. You should allow applications that need
> to run in ancient browsers to compensate by setting inline styles
> (i.e. check inline styles as a fallback.)
>

getComputedStyle. (I set |bcs| in the poll-timer to; bcs =
getComputedStlye(document.body,''))

That is someting I struggled with.

The reason I get it in the poll timer is to improve runtime
performance by reducing a function call to getComputedStyle.

The problem with relying on style attribute is that it's not a
computed pixel style.

<div style="left: 2em">hi</div>

getComputedStyle is (or should be) a pixel value.


> [snip]
>
> ----
> // Loop up, gathering scroll offsets on parentNodes.
> // when we get to a parent that's an offsetParent, update
> // the current offsetParent marker.
>
> I prefer to loop through offsetParents and then deal with scrolling
> parents as an optional afterthought. This makes it easy for
> applications that do not involve scrolling containers to prevent the
> extra work. Also, the adjustments for scrolling containers are needed
> for the gBOF branch.
>

It requires two traversals that way, which would seem to be alot
slower when you need scroll offsets.

I need to do some profiling on this...

> ! (parent.tagName === "TABLE" && IS_TABLE_BORDER_INCLUDED_IN_TD_OFFSET)) {
>
> You don't need a strict comparison there.

That's true algorithm is the same for characters. So it doesn't really
matter, just one extra char.

application/xhtml+xml:

I should call tagName.toLowerCase() == 'table' but that costs more for
each iteration.


> if(false == IS_PARENT_BORDER_INCLUDED_IN_OFFSET
>
> Shouldn't this be !IS_PARENT_BORDER_INCLUDED_IN_OFFSET?
>

I thought it looked clearer to see a blue (my editor uses blue for
keywords) |false| first. When the code gets there, the
IS_PARENT_BORDER_INCLUDED_IN_OFFSET is already set to true or false.


> else if(container === doc || container === documentElement) {
> // If the body is positioned, add its left and top value.
>
> // Safari will sometimes return "auto" for computedStyle, which
> results NaN.
>
> So will IE for statically positioned elements. Opera will return

> incorrect results for those with borders....
>

IE doesn't support computedStyle.
Opera returns wrong results for |left| when the element has a border?
I can't reproduce that.

A browser in the second loop that doesn't support getComputedStyle
will fail horribly. I need to address. Probably
if(getBoundingClientRect){...}
else if(bcs){...}

> (function(){
> var waitForBodyTimer = setInterval(function
> domInitLoadTimeConstants() {
>
> What is this about? A DOM ready simulation?
>

Sort of. It's polling for existence of document.body every 60ms. Are
there any issues with that?

> if(!document.body) return;
>
> This excludes XHTML documents in Windows Safari and (reportedly) some
> older Gecko-based browsers.
>

I use document.body all over the place. I'm not attempting to address
the issue.

> var xs = x.style;
> xs.margin = 0;
> xs.position = "static";
>
> x = body.appendChild(x);
>
> This will cause a twitch during page load. I would make the height
> and width 0 if you can get away with it in this test.
>

Appending a child causes the page to twitch?

body.style.height = 0;
to avoid page flicker?

Would it be better to call
body.insertBefore(x, body.firstChild)
?

I haven't made any example/usability tests. I'll need them, and prob
add some shiny css. The psychological effects of CSS and appearance
are an interesting, but side topic.

>
> Why not use DOM methods and lose the try-catch?

innerHTML is faster and shorter than DOM. I lost the try-catch. It's
an IE innerHTML bug, but IE doesn't get there anyway.

<snip>

> // XXX Safari gets offsetParent wrong (says 'body' when body is static,
> // but then positions element from ICB and then subtracts body's
> clientWidth.
> // Safari is half wrong.
> //
> // XXX Mozilla says body is offsetParent but does NOT subtract
> BODY's offsetWidth.
>
> Subtracts BODY's clientWidth?
>

I meant to
// XXX Mozilla says body is offsetParent but does NOT add el's
negative offsetLeft/Top.

Example:

body {
border: 10px solid red;
margin: 0;
padding: 0;
}

#el {
position: absolute;
top: 0;
left : 0;
}

#el is at 0, 0 from it's containing block, HTML.
El is outside of it's static parentNode (body).
#el is (-10, -10) from the body's inner border edge.

BODY is considered offsetParent (Safari, Webkit, Opera, IE quirks),
even when it's not a containing block. This is following the spec Anne
made up.

el.offsetTop == -10;// Webkit.

el.offsetTOp == 0; // Mozilla.

Mozilla gives the offsetTop/Left values from the offsetParent, like
the MS docs say.

So in Mozilla, the offsetParent is BODY, and el's offsetTop is 0.

This is as per Anne's spec.

Then to compensate for the problem, Mozilla gives BODY an offsetTop/
Left of (-10, -10).

https://bugzilla.mozilla.org/show_bug.cgi?id=255754

> s.position = position;
>
> s.marginTop = marginTop;
> // Put back border and padding the way they were.
> s.border = border;
> s.padding = padding;
>
> This is going to be twitchy.

Suggestions welcome. I'll probably have to work that out.

About the test case: The test case performs ~27 tests, setting
innerHTML on the main content area in setUP and tearDown. It changes
cssText on body, html, and #container in each setUp tearDown.

Then the test case does the same thing all over, calling
window.scrollTo(10, 100);

>
> Sorry for the inevitable wrapping. I didn't have time to make this
> newsreader-friendly.
>

That's about the best review I could ask for. I am considering to
switch from tabs to spaces. I can post code directly here next time.

David Mark

unread,
Feb 18, 2008, 9:51:01 PM2/18/08
to
On Feb 18, 8:05 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
> On Feb 17, 9:01 pm, David Mark <dmark.cins...@gmail.com> wrote:
>
> On Feb 17, 9:01 pm, David Mark <dmark.cins...@gmail.com> wrote:
>
> > On Feb 17, 5:09 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
> > I took a little time to survey this.
>
> It's an excellent review. Questions about comments/x.d/borderColor, I

Thanks.

> just corrected the mistakes and
> snipped the question to keep focused on other things.
>
> >         var IS_BACK_COMPAT = document.compatMode === "BackCompat";
>
> > You can't rely on this flag in IE < 6.
>
> What do you do? There's likely to eventually be a browser that
> supports getBoundingClientRect, yet has document.compatMode ==
> "undefined"

As I mentioned, the new Opera (Beta at this time I think) does indeed
support this method. I don't know whether it supports compatMode or
not. It has been my experience that compatMode tests are largely
useless for anything but IE. The multi-object inference I use to get
around this for IE5 (which has no compatMode property and is always in
quirks mode) is not ideal, but is the best I could come up with. It
won't affect new versions of standards-compliant browsers, so the new
Opera will measure the borders of the HTML element. Who knows if that
will even be necessary with their (or other) future implementations?
I'll test them and make any needed adjustments when they come out. No
matter how robust a solution you have for any given browser scripting
problem, it is no guarantee that future testing will pass with flying
colors.

>
> <snip>
>
> > I use a wrapper that uses border styles in lieu of clientLeft/Top.  I
> > think it makes the code easier to follow.
>
> That would be easier to follow; it would reduce conditional checks and
> put the logic on one place. I was doing this at first, but it was
> slow. I replaced it with inline code and the time
> was cut almost in half.

Certainly. To this end, I try to call functions like this one as
infrequently as possible.

>
> Removing the extra function call made a big difference.
>
> >         // XXX Opera <= 9.2 - parent border widths are included in offsetTop.
> >         var IS_PARENT_BORDER_INCLUDED_IN_OFFSET;
>
> > Can I assume from the comment that this flag will be false in the new
> > Opera?  It doesn't really matter, but it would be good if they changed
> > their scheme to match other browsers.
>
> The flag gets set based on a test:
>
> // A closure for initializing load time constants.
> if(!("getBoundingClientRect"in document.documentElement))
>   (function(){
>     var waitForBodyTimer = setInterval(function
> domInitLoadTimeConstants() {
>       if(!document.body) return;
>
>       clearInterval(waitForBodyTimer);
>
>       var x = document.createElement('div');
>       var xs = x.style;
>       xs.margin = 0;
>       xs.position = "static";
>       x = body.appendChild(x);
>       IS_PARENT_BORDER_INCLUDED_IN_OFFSET = (x.offsetTop === 1);
>   ...
>     }, 60);
>
> })();

I realize that. I was just commenting on the specificity of the
comment with regard to the versions that display this quirk.

>
> <snip>
>
> > A positioned body element is a case I didn't consider.  I am not
> > surprised that such a style causes issues.
>
> It is a very real case. Setting position: relative makes an element a
> containing block for absolutely positioned elements.

Yes, but a positioned *body* element? I've never seen such a thing
and can't imagine a use for it. However, I am all for covering as
many cases as possible (provided the workarounds can be omitted for
applications that don't need them covered.)

>
> For example:
>
> #adiv {
>   position: absolute;
>   top: 0;}
>
> body {
>   margin: 10px;
>
> }

But this is not a positioned body element. (?)

>
> adiv's containing block is HTML. It's offsetParent should be HTML, and
> in IE, it is.

Well, there is no standard for offsetParent yet, so it is hard to say
who is right.

>
> In Opera, Safari, Firefox the offsetParent is BODY. This is per Anne
> van Kesteren's spec.

If that spec ever becomes a standard, then we can say that IE is
wrong.

>
> In Safari, the offsetTop of adiv will be -10. Given the fact that
> adiv's offsetParent is BODY, this makes sense.

None of the browsers seem to agree on absolute/fixed positioned
elements and their relative offsets. As I recall, such cases were
responsible for most of my feature testing and quirk detection.

>
> >         var
> > IS_STATIC_BODY_OFFSET_PARENT_BUT_ABSOLUTE_CHILD_SUBTRACTS_BODY_BORDER_WIDTH
> > = false;
>
> > Borders/margins on the HTML element (in standards mode) cause
> > additional aggravations.
>
> >         var getComputedStyle = window.getComputedStyle;
> >         var bcs;
>
> >         var positionedExp = /^(?:r|a|f)/,
> >                 absoluteExp = /^(?:a|f)/;
>
> > There are several issues that are unique to fixed positioning.  For
> > one, fixed elements in Opera 9 have a null offsetParent.  In this
> > case, I resorted to getComputedStyle.
>
> That would go along with Anne's spec. In the case of fixed
> positioning, I haven't addressed yet.
>
> myFixedDiv.offsetTop
> myFixedDiv.offsetLeft
>
> Would seem to provide the desired result.

IIRC, it doesn't. AIUI, the lack of an offsetParent should result in
a lack of offsetTop/Left properties. But of course, there is no real
standard at this time.

>
> >          * @param {boolean} forceRecalc if true, forces recalculation of body
> > scroll offsets.
>
> > This is an interesting idea.  Is it to make things less painful for
> > applications that don't scroll?
>
> It was an idea for addressing the issue where body's border/margin/
> padding/top/left are unchanging.

That is an assumption that I somewhat embraced (at least in regard to
the adjustment of page origins for fixed positioned elements.) I
think it is too costly to recalculate all of those each time. An
exception would be for applications that switch style sheets to
provide "themes." As I have a module for that, perhaps I should
revisit this issue and at least provide a mechanism to refresh the
data.

>
> It was impossible/extremely difficult to test, and so I removed that.
>
> > Same for Firefox if you use getBoxObjectFor.  For some reason, I
> > didn't do this in the getBoundingClientRect branch, but resorted to
> > the offsetParent loop.  IIRC, IE6/7 had the fewest issues with that
> > method, though I should change it to work like the gBOF branch for
> > performance reasons.
>
> getBoxObjectFor is being discouraged in a bugzilla:https://bugzilla.mozilla.org/show_bug.cgi?id=340571

Oh well. I tested Firefox and Netscape with that branch disabled, so
I am confident I can get rid of it if needed. That being said, I
found gBOF to be very accurate, fast and relatively quirk-free. I'll
have to check out that article before I decide what do there.

>
> It's not supported for HTML. It's not guaranteed to provide any

What is it supported for then?

> results in HTML documents.

I believe I handled the case where it provided an unexpected result,
but I have never run into that in testing.

>
> <snip>
>
>
>
> > Can you elaborate on re-used coords?
>
> If you call getOffsetCoords(el, cont),
>
> it creates an object {x: 0, y: 0};
>
> if you pass in an object
> getBoxOffsetCoords(el. cont, this.coords);
>
> It doesn't create a new object. For drag operations, it could mean
> creating hundreds of objects.

Do you mean for drag operations that have hundreds of drop targets?

>
> //update coords, no need to return anything.
> getOffsetCoords(dropTarget.el, document, dropTarget.coords);
>
> >         function getOffsetCoords(el, container, coords) {
>
> >                 var doc = document, body = doc.body, documentElement =
> > doc.documentElement;
>
> > Apparently this function is good for one document.  I think it is a
> > good idea to allow for multiple documents in functions like these
> > (e.g. for iframes, objects, etc.)
>
> I am too lazy to write a frame-based test. It might work. I guess it
> wouldn't hurt to put in:
>
> doc = el.ownerDocument.

See getElementDocument in the CWR project.

>
> >                 if("getBoundingClientRect"in el) {
>
> > I would avoid the in operator for compatibility reasons.
>
> What copatibility reasons?

There are older browsers that do not support it. Regardless, the
isHostMethod function (also in CWR) has been shown to be the best
solution for this sort of feature detection.

>
> >                         // In BackCompat mode, body's border goes to the window. BODY is
> > ICB.
> >                         var rootBorderEl = (IS_BACK_COMPAT ? body : documentElement);
>
> > But this flag isn't correct in IE < 6 and those versions do not
> > display the documentElement.  IIRC, this is okay in this case as I
> > think IE5.x considers the viewport border to be part of the (otherwise
> > invisible) HTML element.
>
> I don't know how to address this. I don't even have IE6, much less IE
> 5.5 to test on.

I have IE5.0 and IE5.5 installed side-by-side with IE6 on one of my
test boxes. When I get around to re-testing my offset position code,
I will let you know how things turn out. IIRC, I used to resort to
conditional compilation (ecch!) to work around this as IE5.x does have
a documentElement property, but recently switched to a multiple object
inference (still ugly, but at least it minifies properly.) The
primary issue here is that many older browsers (and some newer ones)
do not have a compatMode property, but do have a documentElement,
which may or may not be a part of the layout of the page (in IE5.x it
is not.)

>
> >                         var box = el.getBoundingClientRect();
> >                         var x, y;
> >                         x = box.left - rootBorderEl.clientLeft
> >                                         + Math.max( documentElement.scrollLeft, body.scrollLeft );
> >                         y = box.top - rootBorderEl.clientTop
> >                                         + Math.max( documentElement.scrollTop, body.scrollTop );
> >                         if(container !== doc) {
> >                                 box = getOffsetCoords(container, null);
> >                                 x -= box.x;
> >                                 y -= box.y;
> >                         }
> >                         if(IS_BACK_COMPAT) {
> >                                 var curSty = body.currentStyle;
>
> > Object inference based on getBoundingClientRect (will break in the new
> > Opera.)
>
> That's true, it is object inference. The code assumes:
> if documet.getBoundingClientRect, then body.currentStyle is supported.
> Coincidentally Opera supports currentStyle. It is very likely that
> this

IIRC, the currentStyle property doesn't work very well in Opera.
Thanks for reminding me as I need to revisit this in my unit test for
retrieving cascaded styles.

> will break in future versions of FF/Safari.
>
> Changed to:
> if(IS_BACK_COMPAT && IS_CURRENT_STYLE_SUPPORTED) {
>
>
>
> >                                 x += parseInt(curSty.marginLeft);
> >                                 y += parseInt(curSty.marginTop);
>
> > Use parseFloat.
>
> Am I missing a fraction of a pixel? I think the coords returned should

They add up.

> be integers. I can't remember, but I think I remember IE having
> problems with style values with floating point numbers.

IE will absolutely return cascaded styles with fractions of a pixel
when, for instance, em-based layouts are used.

>
> Using parseInt and parseFloat:
>
> Opera 9.2: (same result for both)
> Expected: 2750  Actual:1794
>
> Safari - parseFloat
> 2750  Actual:2748
>
> Safari - parseInt
> Expected: 2750  Actual:2748
>
> Mozilla - parseFloat:
> Expected: 2750  Actual:2750.734
> Mozilla - parseInt:
> Expected: 2750  Actual:2749
>
> IE - (IE does not get here)
> PASS testGetOffsetLeftFloatingPointEM: passed.
>
> Opera was way off. Forget about accuracy when dealing with EMs in
> Opera.

I haven't had any issues with it. My entire test page is em-based to
deliberately provoke such inconsistencies. I do recall that FF has an
internal round-off error when computing top/left styles of statically
positioned elements.

>
> All browsers fail when using EM. Mozilla would be the closest because
> it keeps floating pixels.

That has not been my experience. I even use an em-based border on the
body of the test page, which is clearly courting disaster (as
intended.) The worst I have seen is a single pixel round-off error in
FF, which I have yet to address as I am 99.9% that it is a problem in
their code (and not an easy one to work around.)

>
> Using Math.round and parseFloat now, I can expect the number to be
> correct in Mozilla. Obviously not good for performance. I will go
> through later and try to profile it. I want to hook a profiler into
> the test runner.
>
> > I need to re-
> > test everything now that I have transplanted the code into a new
> > library (I'm really looking forward to *that*.)
>
> I use a patched version of the YUI test runner. I think it's less
> painful than using JSUnit. I can help you get started with this if you
> want.

Thanks, but I have developed a custom testing framework. Granted,
YUI's is probably better, but I don't have time to mess with it now.

>
>
>
> > What if bcs does not exist.  You should allow applications that need
> > to run in ancient browsers to compensate by setting inline styles
> > (i.e. check inline styles as a fallback.)
>
> getComputedStyle. (I set |bcs| in the poll-timer to; bcs =
> getComputedStlye(document.body,''))

But gCS may not exist, so you should allow applications to compensate
for this in older browsers by mirroring computed styles inline. This
is most important for code that relies on determining a positioned
parent. Certainly it can make a lesser difference for borders,
margins, etc.

>
> That is someting I struggled with.
>
> The reason I get it in the poll timer is to improve runtime
> performance by reducing a function call to getComputedStyle.
>
> The problem with relying on style attribute is that it's not a
> computed pixel style.
>
> <div style="left: 2em">hi</div>

I am aware of that. It is sometimes possible (e.g. in IE) to compute
the proper value. Regardless, an application developer who wishes to
support ancient browsers would be well advised to use pixel units for
certain inline styles (e.g. border.)

>
> getComputedStyle is (or should be) a pixel value.

It is indeed. IIRC, IE's currentStyle property (which is cascaded
rather than computed) returns pixels in IE6 (but not IE7) in at least
some cases.

>
> > [snip]
>
> > ----
> >                                 // Loop up, gathering scroll offsets on parentNodes.
> >                                 // when we get to a parent that's an offsetParent, update
> >                                 // the current offsetParent marker.
>
> > I prefer to loop through offsetParents and then deal with scrolling
> > parents as an optional afterthought.  This makes it easy for
> > applications that do not involve scrolling containers to prevent the
> > extra work.  Also, the adjustments for scrolling containers are needed
> > for the gBOF branch.
>
> It requires two traversals that way, which would seem to be alot
> slower when you need scroll offsets.

Yes, but often much faster when you don't. I think that most
applications will not need to worry about element scroll offsets.

>
> I need to do some profiling on this...
>
> >  ! (parent.tagName === "TABLE" && IS_TABLE_BORDER_INCLUDED_IN_TD_OFFSET)) {
>
> > You don't need a strict comparison there.
>
> That's true algorithm is the same for characters. So it doesn't really
> matter, just one extra char.

My issue with such practices is that it gives me pause when browsing
the code (I have to stop and consider why the === operator is in use
and decide whether it was needed or simply overkill.)

>
> application/xhtml+xml:
>
> I should call tagName.toLowerCase() == 'table' but that costs more for
> each iteration.

Yes, but I think the extra effort is worth it. These sorts of
functions are always going to be a bottleneck, so I endeavor to design
systems that call them as infrequently as possible (if at all.)

>
> > if(false == IS_PARENT_BORDER_INCLUDED_IN_OFFSET
>
> > Shouldn't this be !IS_PARENT_BORDER_INCLUDED_IN_OFFSET?
>
> I thought it looked clearer to see a blue (my editor uses blue for
> keywords) |false| first. When the code gets there, the
> IS_PARENT_BORDER_INCLUDED_IN_OFFSET is already set to true or false.
>
> >                                 else if(container === doc || container === documentElement) {
> >                                         // If the body is positioned, add its left and top value.
>
> >                                         // Safari will sometimes return "auto" for computedStyle, which
> > results NaN.
>
> > So will IE for statically positioned elements.  Opera will return
> > incorrect results for those with borders....
>
> IE doesn't support computedStyle.

I was referring to its cascaded style property (currentStyle), which
IIRC, does return computed styles in some situations (e.g. font sizes
in IE6.) What exactly is a valid computed left or top style for a
statically positioned element? Nothing would seem to make sense.
These styles clearly have no effect on such elements.

> Opera returns wrong results for |left| when the element has a border?
> I can't reproduce that.

It does in my copy of Opera 9 (I forget which revision.) I had to put
a quirk test in for that. Same for height/width. They were always
off by the width of the border(s).

>
> A browser in the second loop that doesn't support getComputedStyle
> will fail horribly. I need to address. Probably
> if(getBoundingClientRect){...}
> else if(bcs){...}
>
> >         (function(){
> >         var waitForBodyTimer = setInterval(function
> > domInitLoadTimeConstants() {
>
> > What is this about?  A DOM ready simulation?
>
> Sort of. It's polling for existence of document.body every 60ms. Are
> there any issues with that?

It just seems like an odd way to go about it. Why not use
attachDocumentReadyListener from CWR?

>
> >                 if(!document.body) return;
>
> > This excludes XHTML documents in Windows Safari and (reportedly) some
> > older Gecko-based browsers.
>
> I use document.body all over the place. I'm not attempting to address
> the issue.

Fair enough.

>
> >                 var xs = x.style;
> >                 xs.margin = 0;
> >                 xs.position = "static";
>
> >                 x = body.appendChild(x);
>
> > This will cause a twitch during page load.  I would make the height
> > and width 0 if you can get away with it in this test.
>
> Appending a child causes the page to twitch?

More specifically, appending and then removing a statically positioned
element will cause the scrollbar to twitch.

>
> body.style.height = 0;
> to avoid page flicker?

I meant the height and width of the appended static element. And I
would avoid assumptions about how host objects type convert values
assigned to their properties.

>
> Would it be better to call
> body.insertBefore(x, body.firstChild)

Then the whole page will twitch (unless x has no height and width.)

> ?
>
> I haven't made any example/usability tests. I'll need them, and prob
> add some shiny css. The psychological effects of CSS and appearance
> are an interesting, but side topic.

For a test page?

>
>
>
> > Why not use DOM methods and lose the try-catch?
>
> innerHTML is faster and shorter than DOM. I lost the try-catch. It's
> an IE innerHTML bug, but IE doesn't get there anyway.

I forget what branch we were talking about. Could future versions of
IE get there? Assuming they do not fix the innerHTML/table problems,
you would have an issue.

Yes, I am quite familiar with that one. It was a major source of pain
until I came up with a viable test for it.

>
> Mozilla gives the offsetTop/Left values from the offsetParent, like
> the MS docs say.
>
> So in Mozilla, the offsetParent is BODY, and el's offsetTop is 0.
>
> This is as per Anne's spec.
>
> Then to compensate for the problem, Mozilla gives BODY an offsetTop/
> Left of (-10, -10).

I know. I cursed them repeatedly when I first ran into that.
Happily, there turned out to be a simple feature test that worked in
all (tested) Gecko-based browsers. At least they are consistent.

>
> https://bugzilla.mozilla.org/show_bug.cgi?id=255754
>
> >                 s.position = position;
>
> >                 s.marginTop = marginTop;
> >                 // Put back border and padding the way they were.
> >                 s.border = border;
> >                 s.padding = padding;
>
> > This is going to be twitchy.
>
> Suggestions welcome. I'll probably have to work that out.

I forget why you were doing that. All I can say at the moment is that
I didn't include such logic in my take on this problem. Perhaps I
ignored the specific case you are testing.

>
> About the test case: The test case performs ~27 tests, setting
> innerHTML on the main content area in setUP and tearDown. It changes
> cssText on body, html, and #container in each setUp tearDown.
>
> Then the test case does the same thing all over, calling
> window.scrollTo(10, 100);

Sounds good. The last thing you want to miscalculate is the
document's scroll position.

>
>
>
> > Sorry for the inevitable wrapping.  I didn't have time to make this
> > newsreader-friendly.
>
> That's about the best review I could ask for. I am considering to
> switch from tabs to spaces. I can post code directly here next time.

I made that switch recently and it makes for easier posting. It is a
little more bloat for unminified builds, but I don't recommend using
those in production anyway.

dhtml

unread,
Feb 19, 2008, 4:15:03 AM2/19/08
to
On Feb 18, 6:51 pm, David Mark <dmark.cins...@gmail.com> wrote:
> On Feb 18, 8:05 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
>
> > On Feb 17, 9:01 pm, David Mark <dmark.cins...@gmail.com> wrote:
>
> > On Feb 17, 9:01 pm, David Mark <dmark.cins...@gmail.com> wrote:
>
> > > On Feb 17, 5:09 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
>

<snip>

>
>
>
> > <snip>
>
> > > A positioned body element is a case I didn't consider. I am not
> > > surprised that such a style causes issues.
>
> > It is a very real case. Setting position: relative makes an element a
> > containing block for absolutely positioned elements.
>
> Yes, but a positioned *body* element? I've never seen such a thing
> and can't imagine a use for it. However, I am all for covering as
> many cases as possible (provided the workarounds can be omitted for
> applications that don't need them covered.)

That way absolutely-positioned children of BODY stay inside body. I do
this a lot.

> > For example:
>
> > #adiv {
> > position: absolute;
> > top: 0;}
>
> > body {
> > margin: 10px;
>
> > }
>
> But this is not a positioned body element. (?)
>
>

And that's why it's weird. You have a 10px margin around body.
#adiv's containing block is HTML.
BODY is not (or shouldn't be) a majical element.

> > adiv's containing block is HTML. It's offsetParent should be HTML, and
> > in IE, it is.
>
> Well, there is no standard for offsetParent yet, so it is hard to say
> who is right.
>

My Definition:
offsetParent - a containing block that is offset by margin or left/top
values.

Anne van kesteren started this 2 years ago:

Editor's Draft 9 December 2007
"1. If any of the following holds true return null and stop this
algorithm:

* A is the root element.
* A is the HTML body element.
* The computed value of the position property for element A is
fixed.

2...

3. Return the nearest ancestor element of A for which at least one of
the following is true and stop this algorithm if such an ancestor is
found:

* The computed value of the position property is not static.
* It is the HTML body element.
* The computed value of the position property of A is static and
the ancestor is one of the following HTML elements: td, th, or table.
"

http://dev.w3.org/cvsweb/csswg/cssom-view/Overview.html?rev=1.2#offset-attributes


> > In Opera, Safari, Firefox the offsetParent is BODY. This is per Anne
> > van Kesteren's spec.
>
> If that spec ever becomes a standard, then we can say that IE is
> wrong.
>

I would hope that this spec be forgotten a new one started.

The spec is self contradictory, and thus impossible to implement
correctly.

What is A's offsetParent?
if A is BODY then
offsetParent is null

As such, A can then have neither offsetTop, nor offsetLeft. BODY can
have margin, top, left, border, and position.

All of these things move the BODY element.

For some reason, containing block doesn't come up in the document at
all. Nor does "initial containing block".

The spec is inaccurate to the point of being almost completely
fictitious. The damage of having such a spec is considerably large.

The damage can be seen in Opera, Mozilla, and Safari. These browsers
have seemed to have attempted to implement the (impossible) spec. None
of them get it right, of course. It's impossible.

This is a simple test that barely scratches the surface
http://dhtmlkitchen.com/ape/test/tests/dom/inline-offsetTop.html


<snip>

> > It's not supported for HTML. It's not guaranteed to provide any
>
> What is it supported for then?
>

getBoxObjectFor is for XUL

> > > Can you elaborate on re-used coords?

<snip>


> Do you mean for drag operations that have hundreds of drop targets?

When checking drop target coords, with scrolling or moving dropTargets
(while dragging), coord checks must be done continually, while
dragging.

There might be a better strategy for checking coords.

> > I am too lazy to write a frame-based test. It might work. I guess it
> > wouldn't hurt to put in:
>

Besides, I've got load-time constant for determining certain things
about the document, those things could easily be different in the
framed document. It is an edge case that is not worth testing. It
might be worth testing to throw an error if el.ownerDocument != doc;
Then the user knows because it fails right away.

> > doc = el.ownerDocument.
>
> See getElementDocument in the CWR project.
>

Why just use ownerDocument?

> > > if("getBoundingClientRect"in el) {
>
> > > I would avoid the in operator for compatibility reasons.
>
> > What copatibility reasons?
>
> There are older browsers that do not support it. Regardless, the
> isHostMethod function (also in CWR) has been shown to be the best
> solution for this sort of feature detection.

I didn't consider that. I reading some old thread where it says that
IE5.0 doesn't support |in|, so my library will break there. I use |in|
a lot. It's really the only way to tell if an object has a property.

> primary issue here is that many older browsers (and some newer ones)
> do not have a compatMode property, but do have a documentElement,
> which may or may not be a part of the layout of the page (in IE5.x it
> is not.)
>

var IS_BACK_COMPAT = document.compatMode === "BackCompat" ||

documentElement && documentElement.clientWidth === 0);

It's a stronger inference than compatMode (value or absence) alone.
Not perfect, but better.

<snip>

> IIRC, the currentStyle property doesn't work very well in Opera.
> Thanks for reminding me as I need to revisit this in my unit test for
> retrieving cascaded styles.

Does getComputedStyle provides more accurate results?

Opera has some css rounding issues anyway IIRC.

getting styles is painful topic worthy of a new group. I can't even
get currentStyle.clip in IE. I found only clipTop/Left, et c.

> > Am I missing a fraction of a pixel? I think the coords returned should
>
> They add up.
>
> > be integers. I can't remember, but I think I remember IE having
> > problems with style values with floating point numbers.
>
> IE will absolutely return cascaded styles with fractions of a pixel
> when, for instance, em-based layouts are used.
>

I was probably confused with setting fontWeight or zIndex.
style.fontWeight = 101 => Error
style.zIndex = 1.2 => Error? I can't remember. IE is less forgiving.


> I haven't had any issues with it. My entire test page is em-based to
> deliberately provoke such inconsistencies. I do recall that FF has an
> internal round-off error when computing top/left styles of statically
> positioned elements.

There are issues with browsers rounding pixel values:
http://groups.google.com/group/comp.infosystems.www.authoring.stylesheets/browse_thread/thread/f0207ec3bd430c83/8ae40d8a59dcaf23?lnk=gst&q=IE7+rounding#8ae40d8a59dcaf23
http://ejohn.org/blog/sub-pixel-problems-in-css/


> That has not been my experience. I even use an em-based border on the
> body of the test page, which is clearly courting disaster (as
> intended.) The worst I have seen is a single pixel round-off error in
> FF, which I have yet to address as I am 99.9% that it is a problem in
> their code (and not an easy one to work around.)

Try using a torture case and you'll see more errors.

I used fontSize = "777px";
with 1.18em on two nested elements.

It's a real torture test. Amazinly, MOzilla got it. webkit's 2px off.

I don't like seeing failing tests, but I'm leaving it in. It's a way
to say:
"if you try to get an exact calcuation off EM units, it might be off a
few px in some edge cases on some browsers."

testGetOffsetLeftFloatingPointEM : function() {
var fontSize = "10px";
var target = document.getElementById("target");
var container = document.getElementById("container");
var c1 = document.getElementById("c1");
document.documentElement.style.fontSize =
document.body.style.fontSize =
c1.style.fontSize =
container.style.fontSize =
target.style.fontSize = "777px";

container.style.borderLeft =
c1.style.borderLeft = "1.18em solid red";
target.style.marginLeft = "1.18em";
target.style.left = 0;
var expected = Math.round(777 * 1.18 * 3);
var actual = dom.getOffsetCoords(target);
Assert.areEqual(expected, actual.x, "getting computed coords from
EM values failed.");
},

> > getComputedStyle. (I set |bcs| in the poll-timer to; bcs =
> > getComputedStlye(document.body,''))
>
> But gCS may not exist, so you should allow applications to compensate
> for this in older browsers by mirroring computed styles inline. This
> is most important for code that relies on determining a positioned
> parent. Certainly it can make a lesser difference for borders,
> margins, etc.

I'm not testing in older browsers. I am going to try to get it going
in IE6, Safari 2, FF 2, Opera 9.

I am going to exit the function if neither getCOmputedStyle nor
getBoundingRect are supported.

> > The problem with relying on style attribute is that it's not a
> > computed pixel style.
>
> > <div style="left: 2em">hi</div>
>
> I am aware of that. It is sometimes possible (e.g. in IE) to compute
> the proper value. Regardless, an application developer who wishes to
> support ancient browsers would be well advised to use pixel units for
> certain inline styles (e.g. border.)

I hope you're not talking about the Dean Edwards hack that's used in
jQuery's css(). I've tested it thoroughly. The rounding errors are as
bad as Opera (or worse).

Using that hack, it's possible to have close results.

style.fontSize = "10px";
style.height= "2em";

You can get an acceptible result.

When I started using bigger numbers, I got rounding errors.

> > getComputedStyle is (or should be) a pixel value.
>
> It is indeed.

Webkit returns 'auto' when margin: auto and left is undeclared.
http://www.dhtmlkitchen.com/test/bug/getComputedStyle.html

IRC, IE's currentStyle property (which is cascaded
> rather than computed) returns pixels in IE6 (but not IE7) in at least
> some cases.

Hmm.

There's also style.pixelTop and curentStyle.pixelTop (Opera).

> Yes, but often much faster when you don't. I think that most
> applications will not need to worry about element scroll offsets.

I need to get that profiler going.

<snip>

> > application/xhtml+xml:
>
> > I should call tagName.toLowerCase() == 'table' but that costs more for
> > each iteration.
>
> Yes, but I think the extra effort is worth it. These sorts of
> functions are always going to be a bottleneck, so I endeavor to design
> systems that call them as infrequently as possible (if at all.)

var TABLE = /[A-Z]/.test(documentElement.tagName) ? "TABLE" : "table";

Now I can use it as a constant:

(parent.tagName === TABLE

> I was referring to its cascaded style property (currentStyle), which
> IIRC, does return computed styles in some situations (e.g. font sizes
> in IE6.) What exactly is a valid computed left or top style for a
> statically positioned element? Nothing would seem to make sense.
> These styles clearly have no effect on such elements.

Only 0 would make sense to me.

When an element has position: static, top and left values do not
apply.

> > Opera returns wrong results for |left| when the element has a border?
> > I can't reproduce that.
>
> It does in my copy of Opera 9 (I forget which revision.) I had to put
> a quirk test in for that. Same for height/width. They were always
> off by the width of the border(s).

I've got Opera 9.25 and it doesn't do that.

> It just seems like an odd way to go about it. Why not use
> attachDocumentReadyListener from CWR?

It seemed simple enough. I guess it's making the code messy the way I
have it?

<snip>

> > I haven't made any example/usability tests. I'll need them, and prob
> > add some shiny css. The psychological effects of CSS and appearance
> > are an interesting, but side topic.
>
> For a test page?
>

Sure, why not?

I've gone and set the height to "0" (string).

I want to see the twitch you mentioned. I generally dislike making
changes without a proven reason.

That's why I need a demo.

> I forget what branch we were talking about. Could future versions of
> IE get there? Assuming they do not fix the innerHTML/table problems,
> you would have an issue.

Only browsers that do not support getBoundingClientRect get there.

> > Example:
>
> > body {
> > border: 10px solid red;
> > margin: 0;
> > padding: 0;
>
> > }
>
> > #el {
> > position: absolute;
> > top: 0;
> > left : 0;
>
> > }
>
> > #el is at 0, 0 from it's containing block, HTML.
> > El is outside of it's static parentNode (body).
> > #el is (-10, -10) from the body's inner border edge.
>
> > BODY is considered offsetParent (Safari, Webkit, Opera, IE quirks),
> > even when it's not a containing block. This is following the spec Anne
> > made up.
>
> > el.offsetTop == -10;// Webkit.
>
> > el.offsetTOp == 0; // Mozilla.
>
> Yes, I am quite familiar with that one. It was a major source of pain
> until I came up with a viable test for it.

I don't doubt that it is and will continue to be a source of pain for
a lot of people, including members of the Webkit team.

I bet they struggled - and will continue to struggle - with Anne van
Kesteren's "unofficial" spec.

I wonder how many man hours (or months) have been put into
compensating for this careless mistake?

> > Mozilla gives the offsetTop/Left values from the offsetParent, like
> > the MS docs say.
>
> > So in Mozilla, the offsetParent is BODY, and el's offsetTop is 0.
>
> > This is as per Anne's spec.
>
> > Then to compensate for the problem, Mozilla gives BODY an offsetTop/
> > Left of (-10, -10).
>
> I know. I cursed them repeatedly when I first ran into that.
> Happily, there turned out to be a simple feature test that worked in
> all (tested) Gecko-based browsers. At least they are consistent.
>

I'm going to have a look at getElementPosition().

> >https://bugzilla.mozilla.org/show_bug.cgi?id=255754
>
> > > s.position = position;
>
> > > s.marginTop = marginTop;
> > > // Put back border and padding the way they were.
> > > s.border = border;
> > > s.padding = padding;
>
> > > This is going to be twitchy.
>
>

> I forget why you were doing that. All I can say at the moment is that
> I didn't include such logic in my take on this problem. Perhaps I
> ignored the specific case you are testing.
>

I can try to take those out, then do some calculations by reading the
styles and doing math.

Since I have the tests in place now, I can see where it breaks when I
change it.

> > About the test case: The test case performs ~27 tests, setting
> > innerHTML on the main content area in setUP and tearDown. It changes
> > cssText on body, html, and #container in each setUp tearDown.
>
> > Then the test case does the same thing all over, calling
> > window.scrollTo(10, 100);
>
> Sounds good. The last thing you want to miscalculate is the
> document's scroll position.

Garrett

David Mark

unread,
Feb 19, 2008, 5:41:25 AM2/19/08
to
On Feb 19, 4:15 am, dhtml <dhtmlkitc...@gmail.com> wrote:
> On Feb 18, 6:51 pm, David Mark <dmark.cins...@gmail.com> wrote:
>
> > On Feb 18, 8:05 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
>
> > > On Feb 17, 9:01 pm, David Mark <dmark.cins...@gmail.com> wrote:
>
> > > On Feb 17, 9:01 pm, David Mark <dmark.cins...@gmail.com> wrote:
>
> > > > On Feb 17, 5:09 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
>
> <snip>
>
>
>
> > > <snip>
>
> > > > A positioned body element is a case I didn't consider.  I am not
> > > > surprised that such a style causes issues.
>
> > > It is a very real case. Setting position: relative makes an element a
> > > containing block for absolutely positioned elements.
>
> > Yes, but a positioned *body* element?  I've never seen such a thing
> > and can't imagine a use for it.  However, I am all for covering as
> > many cases as possible (provided the workarounds can be omitted for
> > applications that don't need them covered.)
>
> That way absolutely-positioned children of BODY stay inside body. I do
> this a lot.

Why? To avoid the bizarre "edge cases" (pun intended) involving the
HTML element?

>
> > > For example:
>
> > > #adiv {
> > >   position: absolute;
> > >   top: 0;}
>
> > > body {
> > >   margin: 10px;
>
> > > }
>
> > But this is not a positioned body element. (?)
>
> And that's why it's weird. You have a 10px margin around body.
> #adiv's containing block is HTML.
> BODY is not (or shouldn't be) a majical element.

Weird is a good description for the behavior of the various browsers
with regard to absolutely positioned elements without positioned
parents. Your strategy of positioning the body seems like a good way
to avoid some of the quirks.

>
> > > adiv's containing block is HTML. It's offsetParent should be HTML, and
> > > in IE, it is.
>
> > Well, there is no standard for offsetParent yet, so it is hard to say
> > who is right.
>
> My Definition:
> offsetParent - a containing block that is offset by margin or left/top
> values.

I assume that is your abridged definition.

>
> Anne van kesteren started this 2 years ago:
>
> Editor's Draft 9 December 2007
> "1. If any of the following holds true return null and stop this
> algorithm:
>
>     * A is the root element.
>     * A is the HTML body element.
>     * The computed value of the position property for element A is
> fixed.
>
> 2...
>
> 3. Return the nearest ancestor element of A for which at least one of
> the following is true and stop this algorithm if such an ancestor is
> found:
>
>     * The computed value of the position property is not static.
>     * It is the HTML body element.
>     * The computed value of the position property of A is static and
> the ancestor is one of the following HTML elements: td, th, or table.
> "
>

> http://dev.w3.org/cvsweb/csswg/cssom-view/Overview.html?rev=1.2#offse...


>
> > > In Opera, Safari, Firefox the offsetParent is BODY. This is per Anne
> > > van Kesteren's spec.
>
> > If that spec ever becomes a standard, then we can say that IE is
> > wrong.
>
> I would hope that this spec be forgotten a new one started.

Yes, I glanced at it recently and it seems out-of-touch with reality.

>
> The spec is self contradictory, and thus impossible to implement
> correctly.

Always a bad thing for a technical specification.

>
> What is A's offsetParent?
> if A is BODY then
> offsetParent is null
>
> As such, A can then have neither offsetTop, nor offsetLeft. BODY can
> have margin, top, left, border, and position.
>
> All of these things move the BODY element.
>
> For some reason, containing block doesn't come up in the document at
> all. Nor does "initial containing block".
>
> The spec is inaccurate to the point of being almost completely
> fictitious. The damage of having such a spec is considerably large.

I agree. Hopefully it will not become the basis for a standard.

>
> The damage can be seen in Opera, Mozilla, and Safari. These browsers
> have seemed to have attempted to implement the (impossible) spec. None
> of them get it right, of course. It's impossible.

Now I know who caused this mess. Thanks Anne!

>
> This is a simple test that barely scratches the surfacehttp://dhtmlkitchen.com/ape/test/tests/dom/inline-offsetTop.html


>
> <snip>
>
> > > It's not supported for HTML. It's not guaranteed to provide any
>
> > What is it supported for then?
>
> getBoxObjectFor is for XUL

Ah, there is only XUL. I wonder why it works so well for (X)HTML
documents? Perhaps it is just a lucky coincidence. I can't remember
where I got the idea to use it, but it seemed like a sound idea at the
time.

>
>
>
> > > > Can you elaborate on re-used coords?
> <snip>
> > Do you mean for drag operations that have hundreds of drop targets?
>
> When checking drop target coords, with scrolling or moving dropTargets
> (while dragging), coord checks must be done continually, while

Drop targets inside of scrolling containers that can be scrolled
during the drag operation I can see. But moving drop targets? Other
than a video game of some sort, the application for that eludes me.

> dragging.
>
> There might be a better strategy for checking coords.

Certainly. For the scrolling example, the dragged element could share
the same positioned parent as the drop targets, which could be
positioned absolutely. Then the overlap logic would only need to use
computed styles.

>
> > > I am too lazy to write a frame-based test. It might work. I guess it
> > > wouldn't hurt to put in:
>
> Besides, I've got load-time constant for determining certain things
> about the document, those things could easily be different in the
> framed document. It is an edge case that is not worth testing. It

Yes, if a document that triggers standards-based layout contains an
IFrame that triggers quirks mode, things could get very ugly. This is
something I need to document.

> might be worth testing to throw an error if el.ownerDocument != doc;
> Then the user knows because it fails right away.
>
> > > doc = el.ownerDocument.
>
> > See getElementDocument in the CWR project.
>
> Why just use ownerDocument?

Because it can't be assumed to be there. The fallback branch isn't
too involved.

>
> > > >                 if("getBoundingClientRect"in el) {
>
> > > > I would avoid the in operator for compatibility reasons.
>
> > > What copatibility reasons?
>
> > There are older browsers that do not support it.  Regardless, the
> > isHostMethod function (also in CWR) has been shown to be the best
> > solution for this sort of feature detection.
>
> I didn't consider that. I reading some old thread where it says that
> IE5.0 doesn't support |in|, so my library will break there. I use |in|

That's the biggest reason I don't use it in low-level code like this.

> a lot. It's really the only way to tell if an object has a property.

See the three methods recently discussed in the thread about Peter's
feature testing article.

>
> > primary issue here is that many older browsers (and some newer ones)
> > do not have a compatMode property, but do have a documentElement,
> > which may or may not be a part of the layout of the page (in IE5.x it
> > is not.)
>
> var IS_BACK_COMPAT = document.compatMode === "BackCompat" ||
> documentElement && documentElement.clientWidth === 0);
>
> It's a stronger inference than compatMode (value or absence) alone.
> Not perfect, but better.

I don't think that will work. For instance, I know the
documentElement in IE5 has a non-zero scrollHeight/Width. I tried
everything to come up with a proper feature test for this. I finally
came up with a partial solution that uses a multiple object inference
only until the page has been scrolled (then it knows for sure which to
use.) In my entire library, this is the only quirk that I couldn't
find a pure feature test for.

>
> <snip>
>
> > IIRC, the currentStyle property doesn't work very well in Opera.
> > Thanks for reminding me as I need to revisit this in my unit test for
> > retrieving cascaded styles.
>
> Does getComputedStyle provides more accurate results?

Well, they are apples and oranges, but other than left/top and height/
width for statically positioned elements, I have found no problems
with getComputedStyle in Opera.

>
> Opera has some css rounding issues anyway IIRC.

I haven't run into those in Opera.

>
> getting styles is painful topic worthy of a new group. I can't even
> get currentStyle.clip in IE. I found only clipTop/Left, et c.

Interesting. IE's implementation of clip is completely bizarre. I
couldn't include a two line function that "unclips" an element in my
core build as it required conditional compilation. For this reason,
it is offered only as an add-on, which is only required for certain
animation effects.

>
> > > Am I missing a fraction of a pixel? I think the coords returned should
>
> > They add up.
>
> > > be integers. I can't remember, but I think I remember IE having
> > > problems with style values with floating point numbers.
>
> > IE will absolutely return cascaded styles with fractions of a pixel
> > when, for instance, em-based layouts are used.
>
> I was probably confused with setting fontWeight or zIndex.
> style.fontWeight = 101 => Error
> style.zIndex = 1.2 => Error? I can't remember. IE is less forgiving.

That looks like a sure error to me.

>
> > I haven't had any issues with it.  My entire test page is em-based to
> > deliberately provoke such inconsistencies.  I do recall that FF has an
> > internal round-off error when computing top/left styles of statically
> > positioned elements.
>

> There are issues with browsers rounding pixel values:http://groups.google.com/group/comp.infosystems.www.authoring.stylesh...http://ejohn.org/blog/sub-pixel-problems-in-css/

Thanks. I'll skip that one.

>
> > That has not been my experience.  I even use an em-based border on the
> > body of the test page, which is clearly courting disaster (as
> > intended.)  The worst I have seen is a single pixel round-off error in
> > FF, which I have yet to address as I am 99.9% that it is a problem in
> > their code (and not an easy one to work around.)
>
> Try using a torture case and you'll see more errors.

My test page layout is fairly torturous I think, but within reasonable
limits.

Here's a really weird one. I have a "grow" effect that can optionally
size the font of the element. Using my em-based layout (which was my
first stab at aligning to a baseline grid), I found that setting
inline font sizes to their cascaded or computed values would make the
fonts change in size (which makes no sense to me) and this only
happened at certain text size settings (e.g. larger, smaller,
smallest, but not medium.) However, if I set the inline font size
style to what I know is the cascaded value before I run the animation,
then all is well (the fonts have already jumped in size.) That is the
one strange workaround I had to implement in all of the animation
tests. I still don't understand what the deal was with that (and
don't really care.) I suspect my CSS is just too convoluted, but the
baseline grid does work well in all of the browsers I have tested.

>
> I used fontSize = "777px";
> with 1.18em on two nested elements.
>
> It's a real torture test. Amazinly, MOzilla got it. webkit's 2px off.

What Webkit browser do you test with? Windows Safari Beta? That
browser still has some serious issues. I wonder if they will ever
finish it. Despite it being a Beta, I duly added some quirk detection
logic in a few places to make the unit tests behave (more as an
exercise in feature testing than anything else.) I still have an
issue when I replace a static (and streaming) Flash movie with one
created on page load (to prevent the "click to activate" problem) and
Safari's status bar indicates that it is still loading the replaced
object element. I've seen it crash when interacting with Apple's own
Quicktime plug-in as well. Whatever.

>
> I don't like seeing failing tests, but I'm leaving it in. It's a way
> to say:
> "if you try to get an exact calcuation off EM units, it might be off a
> few px in some edge cases on some browsers."

Makes sense.

>
> testGetOffsetLeftFloatingPointEM : function() {
>     var fontSize = "10px";
>     var target = document.getElementById("target");
>     var container = document.getElementById("container");
>     var c1 = document.getElementById("c1");
>     document.documentElement.style.fontSize =
>     document.body.style.fontSize =
>         c1.style.fontSize =
>         container.style.fontSize =
>         target.style.fontSize = "777px";
>
>     container.style.borderLeft =
>     c1.style.borderLeft = "1.18em solid red";
>     target.style.marginLeft = "1.18em";
>     target.style.left = 0;
>     var expected = Math.round(777 * 1.18 * 3);
>     var actual = dom.getOffsetCoords(target);
>     Assert.areEqual(expected, actual.x, "getting computed coords from
> EM values failed.");

Interesting.

>
> },
> > > getComputedStyle. (I set |bcs| in the poll-timer to; bcs =
> > > getComputedStlye(document.body,''))
>
> > But gCS may not exist, so you should allow applications to compensate
> > for this in older browsers by mirroring computed styles inline.  This
> > is most important for code that relies on determining a positioned
> > parent.  Certainly it can make a lesser difference for borders,
> > margins, etc.
>
> I'm not testing in older browsers. I am going to try to get it going
> in IE6, Safari 2, FF 2, Opera 9.
>
> I am going to exit the function if neither getCOmputedStyle nor
> getBoundingRect are supported.

To be future-proof, you need getComputedStyle or
(getBoundingClientRect AND clientLeft/Top.)

>
> > > The problem with relying on style attribute is that it's not a
> > > computed pixel style.
>
> > > <div style="left: 2em">hi</div>
>
> > I am aware of that.  It is sometimes possible (e.g. in IE) to compute
> > the proper value.  Regardless, an application developer who wishes to
> > support ancient browsers would be well advised to use pixel units for
> > certain inline styles (e.g. border.)
>
> I hope you're not talking about the Dean Edwards hack that's used in
> jQuery's css(). I've tested it thoroughly. The rounding errors are as
> bad as Opera (or worse).

In the case of IE computing the pixel-based value, I am talking of a
modified version of that hack. It has worked thus far for me. The
unmodified original was clearly no good.

>
> Using that hack, it's possible to have close results.
>
> style.fontSize = "10px";
> style.height= "2em";
>
> You can get an acceptible result.
>
> When I started using bigger numbers, I got rounding errors.

I probably will too. The lesson is that nothing is going to be 100%
perfect for all cases in all browsers. I figure that the best I can
shoot for is 99%. It seems to me that the currently popular libraries
take a stance like "three out of four ain't bad."

>
> > > getComputedStyle is (or should be) a pixel value.
>
> > It is indeed.
>
> Webkit returns 'auto' when margin: auto and left is undeclared.http://www.dhtmlkitchen.com/test/bug/getComputedStyle.html

My gCS wrapper will never return "auto", but instead returns null.

>
> IRC, IE's currentStyle property (which is cascaded
>
> > rather than computed) returns pixels in IE6 (but not IE7) in at least
> > some cases.
>
> Hmm.
>
> There's also style.pixelTop and curentStyle.pixelTop (Opera).

I don't use those, except in the aforementioned hack to convert
cascaded styles to pixel units in an IE-only branch (Opera always uses
getComputedStyle.)

>
> > Yes, but often much faster when you don't.  I think that most
> > applications will not need to worry about element scroll offsets.
>
> I need to get that profiler going.
>
> <snip>
>
> > > application/xhtml+xml:
>
> > > I should call tagName.toLowerCase() == 'table' but that costs more for
> > > each iteration.
>
> > Yes, but I think the extra effort is worth it.  These sorts of
> > functions are always going to be a bottleneck, so I endeavor to design
> > systems that call them as infrequently as possible (if at all.)
>
> var TABLE = /[A-Z]/.test(documentElement.tagName) ? "TABLE" : "table";
>
> Now I can use it as a constant:
>
> (parent.tagName === TABLE

Interesting solution.

>
> > I was referring to its cascaded style property (currentStyle), which
> > IIRC, does return computed styles in some situations (e.g. font sizes
> > in IE6.)  What exactly is a valid computed left or top style for a
> > statically positioned element?  Nothing would seem to make sense.
> > These styles clearly have no effect on such elements.
>
> Only 0 would make sense to me.

Or null I would think. Regardless, Opera, FF and others go ahead and
return what they think is the offset position in pixels (as mentioned,
Opera gets them wrong when borders are involved.)

>
> When an element has position: static, top and left values do not
> apply.

Exactly, so I consider the above-mentioned behavior a non-standard
bonus feature. Needless to say, I do not rely on its presence.

>
> > > Opera returns wrong results for |left| when the element has a border?
> > > I can't reproduce that.
>
> > It does in my copy of Opera 9 (I forget which revision.)  I had to put
> > a quirk test in for that.  Same for height/width.  They were always
> > off by the width of the border(s).
>
> I've got Opera 9.25 and it doesn't do that.

That means they fixed it and my code will skip the workaround in that
and subsequent versions. Isn't feature testing wonderful?

>
> > It just seems like an odd way to go about it.  Why not use
> > attachDocumentReadyListener from CWR?
>
> It seemed simple enough. I guess it's making the code messy the way I
> have it?

It is definitely confusing to see a timeout in there.

>
> <snip>
>
> > > I haven't made any example/usability tests. I'll need them, and prob
> > > add some shiny css. The psychological effects of CSS and appearance
> > > are an interesting, but side topic.
>
> > For a test page?
>
> Sure, why not?

I don't know. It is the last thing I am worried about at the moment.
I figure when I get to the unit test for the style switcher, I will
create some more distinct (and perhaps more appealing) alternate
styles.

>
> I've gone and set the height to "0" (string).

Good.

>
> I want to see the twitch you mentioned. I generally dislike making
> changes without a proven reason.

Think about it. If the statically positioned element added at the
bottom has a height, then the page will grow longer. Removing it will
restore the previous height. Watch the scrollbar closely during the
load and you will see it jump briefly to reflect the change.

>
> That's why I need a demo.
>
> > I forget what branch we were talking about.  Could future versions of
> > IE get there?  Assuming they do not fix the innerHTML/table problems,
> > you would have an issue.
>
> Only browsers that do not support getBoundingClientRect get there.

I see.

>
> > > Example:
>
> > > body {
> > >   border: 10px solid red;
> > >   margin: 0;
> > >   padding: 0;
>
> > > }
>
> > > #el {
> > >   position: absolute;
> > >   top: 0;
> > >   left : 0;
>
> > > }
>
> > > #el is at 0, 0 from it's containing block, HTML.
> > > El is outside of it's static parentNode (body).
> > > #el is (-10, -10) from the body's inner border edge.
>
> > > BODY is considered offsetParent (Safari, Webkit, Opera, IE quirks),
> > > even when it's not a containing block. This is following the spec Anne
> > > made up.
>
> > > el.offsetTop == -10;// Webkit.
>
> > > el.offsetTOp == 0; // Mozilla.
>
> > Yes, I am quite familiar with that one.  It was a major source of pain
> > until I came up with a viable test for it.
>
> I don't doubt that it is and will continue to be a source of pain for
> a lot of people, including members of the Webkit team.
>
> I bet they struggled - and will continue to struggle - with Anne van
> Kesteren's "unofficial" spec.

I imagine so.

>
> I wonder how many man hours (or months) have been put into
> compensating for this careless mistake?

I know I spent at least a few days tearing my hair out over the
various "edge cases" (pun intended.)

>
> > > Mozilla gives the offsetTop/Left values from the offsetParent, like
> > > the MS docs say.
>
> > > So in Mozilla, the offsetParent is BODY, and el's offsetTop is 0.
>
> > > This is as per Anne's spec.
>
> > > Then to compensate for the problem, Mozilla gives BODY an offsetTop/
> > > Left of (-10, -10).
>
> > I know.  I cursed them repeatedly when I first ran into that.
> > Happily, there turned out to be a simple feature test that worked in
> > all (tested) Gecko-based browsers.  At least they are consistent.
>
> I'm going to have a look at getElementPosition().

Have fun.

[snip]

Henry

unread,
Feb 19, 2008, 7:52:37 AM2/19/08
to
On Feb 19, 2:51 am, David Mark wrote:
> On Feb 18, 8:05 pm, dhtml wrote:
<snip>

>> adiv's containing block is HTML. It's offsetParent should be
>> HTML, and in IE, it is.
>
> Well, there is no standard for offsetParent yet, so it is
> hard to say who is right.
>
>> In Opera, Safari, Firefox the offsetParent is BODY. This
>> is per Anne van Kesteren's spec.
>
> If that spec ever becomes a standard, then we can say that
> IE is wrong.
<snip>

That could be said but it would be massively unfair to Microsoft to
retrospectively declare what they have been doing for years with a
property they introduced as being 'wrong'. And Microsoft cannot change
the behaviour of IE with regard to offsetParent just because someone
publishes a retrospective standard. Microsoft's biggest concern is the
IE only Intranet applications belonging to its corporate customers
(the ones they really cannot afford to encourage to stop using
Windows).

This is what happened with the 'add' method of SELECT elements.
Microsoft had an - add - method from IE4, then the W3C 'formalised' it
as part of the HTML DOM, but in a way that was incompatible with what
Microsoft had already done, and Microsoft decided to ignore the W3C
and keep all of the pre existing Intranet applications that were
already using - add - working fine. They elected not to break their
corporate customer's Intranets.

And the solution to this situation is as simple as thinking about the
names a little more. If the 'add' method of SELECT elements had been
named 'addOption' in the W3C spec (or something of the sort) then
Microsoft could have implemented it in their browsers fully in
accordance with the W3C specification and still maintained back-
compatibility with existing code. And we would all have benefited
from that.

No if someone is fool enough to attempt to standardise "offsetParent"
in any way other than formalising precisely what IE already does
(which does not appear to be the approach being taken) then we
probably will not see any single usable approach in the foreseeable
future. On the other hand, if they were defining the precise behaviour
of a set of values called, say, "layoutParent", "layoutLeft",
"layoutTop" and so on, Microsoft would have no reason for not
delivering on that new standard in their next browser, because it
would not break any existing code on any of their commercial
customer's Intranets.

David Mark

unread,
Feb 19, 2008, 11:57:42 AM2/19/08
to
On Feb 19, 7:52 am, Henry <rcornf...@raindrop.co.uk> wrote:
> On Feb 19, 2:51 am, David Mark wrote:> On Feb 18, 8:05 pm, dhtml wrote:
> <snip>
> >> adiv's containing block is HTML. It's offsetParent should be
> >> HTML, and in IE, it is.
>
> > Well, there is no standard for offsetParent yet, so it is
> > hard to say who is right.
>
> >> In Opera, Safari, Firefox the offsetParent is BODY. This
> >> is per Anne van Kesteren's spec.
>
> > If that spec ever becomes a standard, then we can say that
> > IE is wrong.
>
> <snip>
>
> That could be said but it would be massively unfair to Microsoft to

True, it could be taken that way. All I meant was that MS would no
longer be compliant with the standard in this respect.

> retrospectively declare what they have been doing for years with a
> property they introduced as being 'wrong'. And Microsoft cannot change
> the behaviour of IE with regard to offsetParent just because someone
> publishes a retrospective standard. Microsoft's biggest concern is the
> IE only Intranet applications belonging to its corporate customers
> (the ones they really cannot afford to encourage to stop using
> Windows).
>
> This is what happened with the 'add' method of SELECT elements.
> Microsoft had an - add - method from IE4, then the W3C 'formalised' it
> as part of the HTML DOM, but in a way that was incompatible with what
> Microsoft had already done, and Microsoft decided to ignore the W3C
> and keep all of the pre existing Intranet applications that were
> already using - add - working fine. They elected not to break their
> corporate customer's Intranets.

Right.

>
> And the solution to this situation is as simple as thinking about the
> names a little more. If the 'add' method of SELECT elements had been
> named 'addOption' in the W3C spec (or something of the sort) then
> Microsoft could have implemented it in their browsers fully in
> accordance with the W3C specification and still maintained back-
> compatibility with existing code.  And we would all have benefited
> from that.

I agree.

>
> No if someone is fool enough to attempt to standardise "offsetParent"

Apparently someone was.

> in any way other than formalising precisely what IE already does
> (which does not appear to be the approach being taken) then we

It was definitely not the approach taken.

> probably will not see any single usable approach in the foreseeable

Not without a ton of feature testing. The offset* properties are a
real mess.

> future. On the other hand, if they were defining the precise behaviour
> of a set of values called, say, "layoutParent", "layoutLeft",
> "layoutTop" and so on, Microsoft would have no reason for not
> delivering on that new standard in their next browser, because it
> would not break any existing code on any of their commercial
> customer's Intranets.

That would be nice, but I doubt it will happen.

Thomas 'PointedEars' Lahn

unread,
Feb 19, 2008, 2:24:36 PM2/19/08
to
David Mark wrote:
> On Feb 17, 6:57 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
>> else if(el.getBoxObjectFor) {
>>
>> }
>
> Use isHostMethod! Feature testing by boolean type conversion is out.

isHostMethod() as it currently is (trunk), is unnecessarily inefficient:

| var isHostMethod = function(o, m) {
| var t = typeof(o[m]);
| return !!(((t=='function' || t=='object') && o[m]) ||
| t == 'unknown');
| };

Consider this:

function isHostMethod(o, m)
{
var t = typeof o[m];
return (/^(function|object)$/.test(typeof o[m]) && o[m])
|| t == "unknown";
}

Would work in JavaScript 1.2+ (NN 4+), JScript 3.1.3510+ (MSHTML 4.01+),
ECMAScript 3+ (Opera 6+).

If you really need to have it return a boolean value *always* (although
because of implicit type conversion in the calling code that is hardly
required), you can write !!o[m] instead.

CWR code should use spaces for indentation, not tabs.


PointedEars

Thomas 'PointedEars' Lahn

unread,
Feb 19, 2008, 2:30:54 PM2/19/08
to
Thomas 'PointedEars' Lahn wrote:
> isHostMethod() as it currently is (trunk), is unnecessarily inefficient:
>
> | var isHostMethod = function(o, m) {
> | var t = typeof(o[m]);
> | return !!(((t=='function' || t=='object') && o[m]) ||
> | t == 'unknown');
> | };
>
> Consider this:
>
> function isHostMethod(o, m)
> {
> var t = typeof o[m];
> return (/^(function|object)$/.test(typeof o[m]) && o[m])
> || t == "unknown";
> }

I meant

function isHostMethod(o, m)
{
var t = typeof o[m];

return (/^(function|object)$/.test(t) && o[m])
|| t == "unknown";
}

of course.


PointedEars

David Mark

unread,
Feb 19, 2008, 2:39:34 PM2/19/08
to
On Feb 19, 2:24 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> David Mark wrote:
> > On Feb 17, 6:57 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
> >> else if(el.getBoxObjectFor) {
>
> >> }
>
> > Use isHostMethod!  Feature testing by boolean type conversion is out.
>
> isHostMethod() as it currently is (trunk), is unnecessarily inefficient:
>
> | var isHostMethod = function(o, m) {
> |   var t = typeof(o[m]);
> |   return !!(((t=='function' || t=='object') && o[m]) ||
> |             t == 'unknown');
> | };
>
> Consider this:
>
>   function isHostMethod(o, m)
>   {
>     var t = typeof o[m];
>     return (/^(function|object)$/.test(typeof o[m]) && o[m])
>            || t == "unknown";
>   }
>

My posted version uses a regexp, but not a literal. Peter asserts
that the other way is faster.

> Would work in JavaScript 1.2+ (NN 4+), JScript 3.1.3510+ (MSHTML 4.01+),
> ECMAScript 3+ (Opera 6+).

Regular expression literals work in IE4 and NN4?

>
> If you really need to have it return a boolean value *always* (although
> because of implicit type conversion in the calling code that is hardly
> required), you can write !!o[m] instead.

Yes, that is roughly what I did. I don't think it makes sense to
return a truthy property of the o object.

>
> CWR code should use spaces for indentation, not tabs.

It does in general. Apparently that early entry did not.

Thanks for the constructive input "PointedEars." I should duly note
that the isHostMethod function owes a debt to your isMethodType
function.

Thomas 'PointedEars' Lahn

unread,
Feb 19, 2008, 2:58:21 PM2/19/08
to
David Mark wrote:

> [...] Thomas 'PointedEars' Lahn [...] wrote:
>> David Mark wrote:
>>> On Feb 17, 6:57 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
>>>> else if(el.getBoxObjectFor) {
>>>> }
>>> Use isHostMethod! Feature testing by boolean type conversion is out.
>> isHostMethod() as it currently is (trunk), is unnecessarily inefficient:
>>
>> | var isHostMethod = function(o, m) {
>> | var t = typeof(o[m]);
>> | return !!(((t=='function' || t=='object') && o[m]) ||
>> | t == 'unknown');
>> | };
>>
>> Consider this:
>>
>> function isHostMethod(o, m)
>> {
>> var t = typeof o[m];
>> return (/^(function|object)$/.test(typeof o[m]) && o[m])
>> || t == "unknown";
>> }
>
> My posted version uses a regexp, but not a literal. Peter asserts
> that the other way is faster.

Interesting. I will have to do more benchmarks.

>> Would work in JavaScript 1.2+ (NN 4+), JScript 3.1.3510+ (MSHTML 4.01+),
>> ECMAScript 3+ (Opera 6+).
>
> Regular expression literals work in IE4 and NN4?

Yes, they do (it's tested), as long as they don't include the multi-line
modifier (`m'). The latter is only supported since JavaScript 1.5
(Mozilla/5.0), JScript 5.5.6330 (MSHTML 5.5), ECMAScript 3 (Opera 6*).

See also http://PointedEars.de/scripts/es-matrix/

* This is an assumption based on <http://www.opera.com/docs/specs/opera6/>.
As always, feedback including test results of language features is
appreciated.

> Thanks for the constructive input "PointedEars."

You're welcome. You may use my nickname without quotes, or my first name.

> I should duly note that the isHostMethod function owes a debt to your
> isMethodType function.

I would appreciate that.


PointedEars
--
Prototype.js was written by people who don't know javascript for people
who don't know javascript. People who don't know javascript are not
the best source of advice on designing systems that use javascript.
-- Richard Cornford, cljs, <f806at$ail$1$8300...@news.demon.co.uk>

David Mark

unread,
Feb 19, 2008, 3:05:24 PM2/19/08
to
On Feb 19, 2:58 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

Good to know.

>
> See alsohttp://PointedEars.de/scripts/es-matrix/


>
> * This is an assumption based on <http://www.opera.com/docs/specs/opera6/>.
>   As always, feedback including test results of language features is
>   appreciated.
>
> > Thanks for the constructive input "PointedEars."
>
> You're welcome.  You may use my nickname without quotes, or my first name.
>
> > I should duly note that the isHostMethod function owes a debt to your
> > isMethodType function.
>
> I would appreciate that.
>

It has been duly noted. This is about as official as it gets for
CWR. There are no credits in the comments AFAIK (everything is
credited to the group as a whole.) I will make a note in my project
though.

dhtml

unread,
Feb 19, 2008, 3:40:59 PM2/19/08
to
On Feb 19, 2:41 am, David Mark <dmark.cins...@gmail.com> wrote:
> On Feb 19, 4:15 am, dhtml <dhtmlkitc...@gmail.com> wrote:
>
> > On Feb 18, 6:51 pm, David Mark <dmark.cins...@gmail.com> wrote:
>
> > > On Feb 18, 8:05 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
>
> > > > On Feb 17, 9:01 pm, David Mark <dmark.cins...@gmail.com> wrote:
>
> > > > On Feb 17, 9:01 pm, David Mark <dmark.cins...@gmail.com> wrote:
>
> > > > > On Feb 17, 5:09 pm, dhtml <dhtmlkitc...@gmail.com> wrote:

<snip>

> > > > > A positioned body element is a case I didn't consider. I am not


> > > > > surprised that such a style causes issues.
>
> > > > It is a very real case. Setting position: relative makes an element a
> > > > containing block for absolutely positioned elements.
>
> > > Yes, but a positioned *body* element? I've never seen such a thing
> > > and can't imagine a use for it. However, I am all for covering as
> > > many cases as possible (provided the workarounds can be omitted for
> > > applications that don't need them covered.)
>
> > That way absolutely-positioned children of BODY stay inside body. I do
> > this a lot.
>
> Why? To avoid the bizarre "edge cases" (pun intended) involving the
> HTML element?

Mostly so I can visually keep everything inside BODY. Sometimes
layouts use a main #container div. I just use BODY position: relative;

so instead of
BODY - static
#main-content - relative

I just have
BODY - relative

> Weird is a good description for the behavior of the various browsers
> with regard to absolutely positioned elements without positioned
> parents. Your strategy of positioning the body seems like a good way
> to avoid some of the quirks.

The problem is, really, it makes harder to calculate the offset
position in Opera.

> > > > adiv's containing block is HTML. It's offsetParent should be HTML, and
> > > > in IE, it is.
>
> > > Well, there is no standard for offsetParent yet, so it is hard to say
> > > who is right.
>
> > My Definition:
> > offsetParent - a containing block that is offset by margin or left/top
> > values.
>
> I assume that is your abridged definition.

A TD, TR, or TBODY that does not have a positioned ancestor should use
its TABLE.

Feel free to add to it.

> Ah, there is only XUL. I wonder why it works so well for (X)HTML
> documents? Perhaps it is just a lucky coincidence. I can't remember
> where I got the idea to use it, but it seemed like a sound idea at the
> time.

The bug report said it best, and this is the worst part:

"-- in Mozilla, it's only available when XUL is enabled, so some
embedded Geckos
don't have it --- actually, it's worse, they have the function, but it
always
fails"
https://bugzilla.mozilla.org/show_bug.cgi?id=340571

> > > > > Can you elaborate on re-used coords?

<partial snip about reused coords>

> Certainly. For the scrolling example, the dragged element could share
> the same positioned parent as the drop targets, which could be
> positioned absolutely. Then the overlap logic would only need to use
> computed styles.

Dualling scrollable lists would have different containing blocks.

#outer-cont
#list-1-cont #list-2-cont

I should probably worry about that when I get to it, and it probably
wouldn't be hard enough to optimize to the point that reusing coords
was pointless.

> Yes, if a document that triggers standards-based layout contains an
> IFrame that triggers quirks mode, things could get very ugly. This is
> something I need to document.

Or if an HTML containing a frame loaded as application/xhtml+xml, and
I had a constant TABLE == "TABLE"
(less likely)


> > Why just use ownerDocument?
>
> Because it can't be assumed to be there. The fallback branch isn't
> too involved.

The only time I could think is if it's in abstract view.

> See the three methods recently discussed in the thread about Peter's
> feature testing article.

function isHostObject(object, property) {
return !!(typeof(object[property]) == 'object' && object[property]);
}

would work.

> > > primary issue here is that many older browsers (and some newer ones)
> > > do not have a compatMode property, but do have a documentElement,
> > > which may or may not be a part of the layout of the page (in IE5.x it
> > > is not.)
>
> > var IS_BACK_COMPAT = document.compatMode === "BackCompat" ||
> > documentElement && documentElement.clientWidth === 0);
>
> > It's a stronger inference than compatMode (value or absence) alone.
> > Not perfect, but better.
>
> I don't think that will work. For instance, I know the
> documentElement in IE5 has a non-zero scrollHeight/Width. I tried
> everything to come up with a proper feature test for this. I finally
> came up with a partial solution that uses a multiple object inference
> only until the page has been scrolled (then it knows for sure which to
> use.) In my entire library, this is the only quirk that I couldn't
> find a pure feature test for.

IE5 propagates viewport dimensions to BODY, but you've pointed out a
case where there's documentElement.scrollWidth.

http://13thparallel.com/archive/viewport/example2.htm

Three possibilities where my approach will fail:
getBoundingClientRect supported, and:
compatMode = undefined, document rendered standard => fails by
incorrectly subtracting body border width
compatMode = BackCompat, document rendered IE quirls => ditto
compatMode = BackCompat, document rendered Moz quirls => ditto

The only reason those bugs aren't apparent is that only IE supports
getBoundingClientRect.

So compatMode is out. It means different things in different
browsers.

// True only in IE5, or IE6+ quirks mode.
var IS_BODY_ACTING_ROOT = documentElement &&
documentElement.clientWidth === 0;

This seems to be true only in IE5, or IE6+ in quirks mode. I don'

> > Opera has some css rounding issues anyway IIRC.
>
> I haven't run into those in Opera.

It goes to those sub-pixel measurements.

When converting an em to px, for clientWidth, I get an uint.

el.style.border='1.92em solid red';
el.clientWidth => 18em;

When using larger numbers for font size, it becomes apparent that
there's also some internal miscalcuation. The numbers aren't off by 1.
They're off by a lot.

When cumulatively adding clientLeft/Top the rounded pixelValues are
added up, resulting in a much more skewed result.

> > > IE will absolutely return cascaded styles with fractions of a pixel
> > > when, for instance, em-based layouts are used.
>
> > I was probably confused with setting fontWeight or zIndex.
> > style.fontWeight = 101 => Error
> > style.zIndex = 1.2 => Error? I can't remember. IE is less forgiving.
>
> That looks like a sure error to me.
>

Sorry, zIndex works with floating points. It was the fontSize that
didn't work with anything other than 100,200...900 (or keyword)

> Here's a really weird one. I have a "grow" effect that can optionally
> size the font of the element. Using my em-based layout (which was my
> first stab at aligning to a baseline grid), I found that setting
> inline font sizes to their cascaded or computed values would make the
> fonts change in size (which makes no sense to me) and this only
> happened at certain text size settings (e.g. larger, smaller,
> smallest, but not medium.) However, if I set the inline font size
> style to what I know is the cascaded value before I run the animation,
> then all is well (the fonts have already jumped in size.)

Try putting what you know to be cascade in the style attribute.

Try inspecting the currentStyle (if this is IE we're talking a

That is the
> one strange workaround I had to implement in all of the animation
> tests. I still don't understand what the deal was with that (and
> don't really care.) I suspect my CSS is just too convoluted, but the
> baseline grid does work well in all of the browsers I have tested.

> What Webkit browser do you test with? Windows Safari Beta?
Yes, and also mac Safari 2 and Webkit recent build.

That
> browser still has some serious issues.

It's fast. It's a lot more standards than Opera.

<snip>

> I probably will too. The lesson is that nothing is going to be 100%
> perfect for all cases in all browsers. I figure that the best I can
> shoot for is 99%. It seems to me that the currently popular libraries
> take a stance like "three out of four ain't bad."

There are cases of working, not working, or somewhere in between. It
works, but it's buggy/returns inaccurate results. I guess there's a
degree of acceptibility in "not quite working" that I'm not
considering. I'll try to just take what I know about degradation and
old browser bugs and try not to cause problems. I don't like thinking
about that too much; though. Having conditions for browsers I can't
test in complicates the code.

<snip>

> > > > getComputedStyle is (or should be) a pixel value.
>
> > > It is indeed.
>
> > Webkit returns 'auto' when margin: auto and left is undeclared.http://www.dhtmlkitchen.com/test/bug/getComputedStyle.html
>
> My gCS wrapper will never return "auto", but instead returns null.

I would probably return an empty string. to avoid having to write:

if(val != null && val != "")

<snip>

> > (parent.tagName === TABLE
>
> Interesting solution.

var TABLE = /^h/.test(documentElement.tagName) ? "table" : "TABLE";

Shorter.

<snip about computed styles>

> > > > Opera returns wrong results for |left| when the element has a border?
> > > > I can't reproduce that.
>
> > > It does in my copy of Opera 9 (I forget which revision.) I had to put
> > > a quirk test in for that. Same for height/width. They were always
> > > off by the width of the border(s).
>
> > I've got Opera 9.25 and it doesn't do that.
>
> That means they fixed it and my code will skip the workaround in that
> and subsequent versions. Isn't feature testing wonderful?

Doesn't mean they fixed a bug. It means you've got a workaround for
something that I can't reproduce.

There are bugs in Opera's left values that I am aware of, but they
come from margins.
http://www.dhtmlkitchen.com/test/bug/getComputedStyle.html

Those two divs at the top? getPropertyValue('left') should be '0'.
Opera returns '8px', which comes from the body's margin.

Maybe a complication of trying to implement the CSSOM views spec.

> > > It just seems like an odd way to go about it. Why not use
> > > attachDocumentReadyListener from CWR?
>
> > It seemed simple enough. I guess it's making the code messy the way I
> > have it?
>
> It is definitely confusing to see a timeout in there.

Hmm.
I want to do this as soon as body is reached.

<snip>

> I don't know. It is the last thing I am worried about at the moment.
> I figure when I get to the unit test for the style switcher, I will
> create some more distinct (and perhaps more appealing) alternate
> styles.

Yeah, it's not priority. Code first. But if there's blinking
scrollbars caused by my code, that's bad.

<snip>

> > I want to see the twitch you mentioned. I generally dislike making
> > changes without a proven reason.
>
> Think about it. If the statically positioned element added at the
> bottom has a height, then the page will grow longer. Removing it will
> restore the previous height. Watch the scrollbar closely during the
> load and you will see it jump briefly to reflect the change.

When I think about it, I'm a little worried about the tree structure
being wrong.

<body>
<div>
<p>..parsing...
appendChild called -> <div/>

That would be an error that should not happen, but with invalid HTML,
anything is possible.

So if |x| is appended to body with height: 0, then there's no reflow?
What about if it has a width?

> > That's why I need a demo.

<snip>

Garrett

David Mark

unread,
Feb 19, 2008, 9:25:14 PM2/19/08
to

I like that! I am often guilty of adding an extra container div to
otherwise semantic markup. I will consider this for future multi-
column layouts.

>
> > Weird is a good description for the behavior of the various browsers
> > with regard to absolutely positioned elements without positioned
> > parents. Your strategy of positioning the body seems like a good way
> > to avoid some of the quirks.
>
> The problem is, really, it makes harder to calculate the offset
> position in Opera.

It certainly doesn't help.

>
> > > > > adiv's containing block is HTML. It's offsetParent should be HTML, and
> > > > > in IE, it is.
>
> > > > Well, there is no standard for offsetParent yet, so it is hard to say
> > > > who is right.
>
> > > My Definition:
> > > offsetParent - a containing block that is offset by margin or left/top
> > > values.
>
> > I assume that is your abridged definition.
>
> A TD, TR, or TBODY that does not have a positioned ancestor should use
> its TABLE.
>
> Feel free to add to it.

I'll see if I can come up with some additional verbage.

>
> > Ah, there is only XUL. I wonder why it works so well for (X)HTML
> > documents? Perhaps it is just a lucky coincidence. I can't remember
> > where I got the idea to use it, but it seemed like a sound idea at the
> > time.
>
> The bug report said it best, and this is the worst part:
>
> "-- in Mozilla, it's only available when XUL is enabled, so some
> embedded Geckos
> don't have it --- actually, it's worse, they have the function, but it
> always
> fails"https://bugzilla.mozilla.org/show_bug.cgi?id=340571

Oops. Fails how? If it returns something falsy, then I am covered.
If it blows up, I need to remove it immediately (which I should
probably do anyway.) It looks like they (and others) are going to
move on to getBoundingClientRect and NOT implement the IE chrome
border quirk. That will require an additional (trivial) feature test.

>
> > > > > > Can you elaborate on re-used coords?
>
> <partial snip about reused coords>
>
> > Certainly. For the scrolling example, the dragged element could share
> > the same positioned parent as the drop targets, which could be
> > positioned absolutely. Then the overlap logic would only need to use
> > computed styles.
>
> Dualling scrollable lists would have different containing blocks.

Right.

>
> #outer-cont
> #list-1-cont #list-2-cont
>
> I should probably worry about that when I get to it, and it probably

That's my strategy for high-level UI components like scrolling lists
with draggable items. I need to make sure the foundation is sound
before considering such things. I do plan to port my popup menus to
use the re-packaged API soon after the Beta release, partly as a
simple example and partly because I need them for other things I am
doing.

> wouldn't be hard enough to optimize to the point that reusing coords
> was pointless.

Probably.

>
> > Yes, if a document that triggers standards-based layout contains an
> > IFrame that triggers quirks mode, things could get very ugly. This is
> > something I need to document.
>
> Or if an HTML containing a frame loaded as application/xhtml+xml, and
> I had a constant TABLE == "TABLE"
> (less likely)

Yes, that would be a strange application.

>
> > > Why just use ownerDocument?
>
> > Because it can't be assumed to be there. The fallback branch isn't
> > too involved.
>
> The only time I could think is if it's in abstract view.

I was referring to ancient browsers. Can you elaborate on your point?

>
> > See the three methods recently discussed in the thread about Peter's
> > feature testing article.
>
> function isHostObject(object, property) {
> return !!(typeof(object[property]) == 'object' && object[property]);
>
> }
>
> would work.

All three work and each has its own specific purpose.

>
> > > > primary issue here is that many older browsers (and some newer ones)
> > > > do not have a compatMode property, but do have a documentElement,
> > > > which may or may not be a part of the layout of the page (in IE5.x it
> > > > is not.)
>
> > > var IS_BACK_COMPAT = document.compatMode === "BackCompat" ||
> > > documentElement && documentElement.clientWidth === 0);
>
> > > It's a stronger inference than compatMode (value or absence) alone.
> > > Not perfect, but better.
>
> > I don't think that will work. For instance, I know the
> > documentElement in IE5 has a non-zero scrollHeight/Width. I tried
> > everything to come up with a proper feature test for this. I finally
> > came up with a partial solution that uses a multiple object inference
> > only until the page has been scrolled (then it knows for sure which to
> > use.) In my entire library, this is the only quirk that I couldn't
> > find a pure feature test for.
>
> IE5 propagates viewport dimensions to BODY, but you've pointed out a
> case where there's documentElement.scrollWidth.

Don't ask me why IE5 does that though. Perhaps IE considers the
chrome border to be the only visible part of the documentElement.

>
> http://13thparallel.com/archive/viewport/example2.htm
>
> Three possibilities where my approach will fail:
> getBoundingClientRect supported, and:
> compatMode = undefined, document rendered standard => fails by
> incorrectly subtracting body border width

Right.

> compatMode = BackCompat, document rendered IE quirls => ditto

Why would this one fail? BackCompat => IE quirks mode => body has the
chrome border.

> compatMode = BackCompat, document rendered Moz quirls => ditto

We'll have to wait and see what Moz does with getBoundingClientRect
and the chrome borders quirk.

>
> The only reason those bugs aren't apparent is that only IE supports
> getBoundingClientRect.
>
> So compatMode is out. It means different things in different
> browsers.

It can still be part of various tests, just not the only test. That
is how I have always treated it. If you test for "CSS" instead of
"BackCompat", you at least know that the HTML element is rendered. It
is when it is "BackCompat" or undefined that there is an ambiguity. I
just checked my code and it looks like I can lose it altogether.

>
> // True only in IE5, or IE6+ quirks mode.
> var IS_BODY_ACTING_ROOT = documentElement &&
> documentElement.clientWidth === 0;

I just tested this and you are right. Stupid me! When looking for a
feature test for IE5 (for viewport size and document scroll size), I
checked the scrollWidth/Height properties (which do evaluate to non-
zero numbers), but must not have checked the clientWidth/Height
properties (which do indeed return 0!) I updated my code accordingly.

Thanks. I had one (multiple) object inference and now there are
none! Good thing too as it was a really ugly one.

>
> This seems to be true only in IE5, or IE6+ in quirks mode. I don'
>
> > > Opera has some css rounding issues anyway IIRC.
>
> > I haven't run into those in Opera.
>
> It goes to those sub-pixel measurements.
>
> When converting an em to px, for clientWidth, I get an uint.
>
> el.style.border='1.92em solid red';
> el.clientWidth => 18em;

I don't follow that. Where did you convert to px and how can
clientWidth be in anything but pixels? I assume the second line has a
typo.

What does the computed border width evaluate to? I suppose it doesn't
matter much as I use clientLeft/Top when available, which are always
going to be rounded in whatever way the browser sees fit. Oh well,
none of this is going to be perfect for every possible layout.

>
> When using larger numbers for font size, it becomes apparent that
> there's also some internal miscalcuation. The numbers aren't off by 1.
> They're off by a lot.

I see.

>
> When cumulatively adding clientLeft/Top the rounded pixelValues are
> added up, resulting in a much more skewed result.

This sounds like a good case for using gCS in the offset position
function, ignoring clientLeft/Top. I think I will do that.

>
> > > > IE will absolutely return cascaded styles with fractions of a pixel
> > > > when, for instance, em-based layouts are used.
>
> > > I was probably confused with setting fontWeight or zIndex.
> > > style.fontWeight = 101 => Error
> > > style.zIndex = 1.2 => Error? I can't remember. IE is less forgiving.
>
> > That looks like a sure error to me.
>
> Sorry, zIndex works with floating points. It was the fontSize that
> didn't work with anything other than 100,200...900 (or keyword)

Did you mean fontWeight? And I did not know you could have non-
integer zIndex values. I can't imagine a use for them though.

>
> > Here's a really weird one. I have a "grow" effect that can optionally
> > size the font of the element. Using my em-based layout (which was my
> > first stab at aligning to a baseline grid), I found that setting
> > inline font sizes to their cascaded or computed values would make the
> > fonts change in size (which makes no sense to me) and this only
> > happened at certain text size settings (e.g. larger, smaller,
> > smallest, but not medium.) However, if I set the inline font size
> > style to what I know is the cascaded value before I run the animation,
> > then all is well (the fonts have already jumped in size.)
>
> Try putting what you know to be cascade in the style attribute.

That's what I do (in IE.)

>
> Try inspecting the currentStyle (if this is IE we're talking a

The issue I mentioned is present in most browsers.

Has Google mangled your post here? The quotes seem to trail off. I
would expect currentStyle to stay the same, but in this case I imagine
it does not (at least at certain font size settings.) Now why on
earth would that be? And BTW, ever test any of this stuff with zoom
enabled in IE7? That feature is so buggy that I don't really care
about it, but I suspect it will amplify weird cases like this.

>
> That is the
>
> > one strange workaround I had to implement in all of the animation
> > tests. I still don't understand what the deal was with that (and
> > don't really care.) I suspect my CSS is just too convoluted, but the
> > baseline grid does work well in all of the browsers I have tested.
> > What Webkit browser do you test with? Windows Safari Beta?
>
> Yes, and also mac Safari 2 and Webkit recent build.

Well, I'll try your unit tests in IE5.x and perhaps you can try mine
in the Mac Safari browsers (I have heard hey differ wildly from the
Windows Beta.)

>
> That> browser still has some serious issues.
>
> It's fast. It's a lot more standards than Opera.

It is indeed fast at DOM traversal and perhaps a tie with IE for
smooth animations. It seems to take a bit longer to load (pages and
itself) than other browsers.

I like the font rendering too.

>
> <snip>
>
> > I probably will too. The lesson is that nothing is going to be 100%
> > perfect for all cases in all browsers. I figure that the best I can
> > shoot for is 99%. It seems to me that the currently popular libraries
> > take a stance like "three out of four ain't bad."
>
> There are cases of working, not working, or somewhere in between. It
> works, but it's buggy/returns inaccurate results. I guess there's a
> degree of acceptibility in "not quite working" that I'm not
> considering. I'll try to just take what I know about degradation and
> old browser bugs and try not to cause problems. I don't like thinking
> about that too much; though. Having conditions for browsers I can't
> test in complicates the code.

That's always a concern.

>
> <snip>
>
> > > > > getComputedStyle is (or should be) a pixel value.
>
> > > > It is indeed.
>
> > > Webkit returns 'auto' when margin: auto and left is undeclared.http://www.dhtmlkitchen.com/test/bug/getComputedStyle.html
>
> > My gCS wrapper will never return "auto", but instead returns null.
>
> I would probably return an empty string. to avoid having to write:
>
> if(val != null && val != "")

But when would the computed style ever be an empty string? I know
cases where it can be null (e.g. display:none makes all of them null
in some browsers), but an empty string?

>
> <snip>
>
> > > (parent.tagName === TABLE
>
> > Interesting solution.
>
> var TABLE = /^h/.test(documentElement.tagName) ? "table" : "TABLE";
>
> Shorter.
>
> <snip about computed styles>
>
> > > > > Opera returns wrong results for |left| when the element has a border?
> > > > > I can't reproduce that.
>
> > > > It does in my copy of Opera 9 (I forget which revision.) I had to put
> > > > a quirk test in for that. Same for height/width. They were always
> > > > off by the width of the border(s).
>
> > > I've got Opera 9.25 and it doesn't do that.
>
> > That means they fixed it and my code will skip the workaround in that
> > and subsequent versions. Isn't feature testing wonderful?
>
> Doesn't mean they fixed a bug. It means you've got a workaround for
> something that I can't reproduce.

Trust me, you'd be able to reproduce this easily enough. Just get the
computed height/width style of any element with a border. When this
bug is present, the border is included in the dimensions (!) From
looking at my test for this, they don't have to be statically
positioned (as previously reported.) As for the similar left/top
issue, from looking at my test, it is either not exactly as I
remembered (and reported) it or I botched the test code when I
transplanted it into the library (doubtful.) I will have to re-test
that case.

>
> There are bugs in Opera's left values that I am aware of, but they
> come from margins.http://www.dhtmlkitchen.com/test/bug/getComputedStyle.html

My test code is currently testing whether the border width of a
positioned parent is included (which isn't what I remembered it
doing.) Could be the same issue. Regardless, I have a bullet-proof
way of fixing problems with computed dimensions and positions that
also accounts for box model differences.

>
> Those two divs at the top? getPropertyValue('left') should be '0'.
> Opera returns '8px', which comes from the body's margin.

That will happen with borders too. Apparently my test is correct, but
I just remembered the bug wrong. I typically try to forget bugs once
a feature test has been proven to work around them. As an aside, I
wonder if anyone out there reading this thread still thinks that
browser sniffing is either necessary or a good idea.

>
> Maybe a complication of trying to implement the CSSOM views spec.

The what?

>
> > > > It just seems like an odd way to go about it. Why not use
> > > > attachDocumentReadyListener from CWR?
>
> > > It seemed simple enough. I guess it's making the code messy the way I
> > > have it?
>
> > It is definitely confusing to see a timeout in there.
>
> Hmm.
> I want to do this as soon as body is reached.

Do you mean as soon as it has finished parsing (i.e. the end tag has
been processed.)

>
> <snip>
>
> > I don't know. It is the last thing I am worried about at the moment.
> > I figure when I get to the unit test for the style switcher, I will
> > create some more distinct (and perhaps more appealing) alternate
> > styles.
>
> Yeah, it's not priority. Code first. But if there's blinking
> scrollbars caused by my code, that's bad.

Yes, such twitches can seriously detract from the initial
presentation.

>
> <snip>
>
> > > I want to see the twitch you mentioned. I generally dislike making
> > > changes without a proven reason.
>
> > Think about it. If the statically positioned element added at the
> > bottom has a height, then the page will grow longer. Removing it will
> > restore the previous height. Watch the scrollbar closely during the
> > load and you will see it jump briefly to reflect the change.
>
> When I think about it, I'm a little worried about the tree structure
> being wrong.
>
> <body>
> <div>
> <p>..parsing...
> appendChild called -> <div/>

You lost me there.

>
> That would be an error that should not happen, but with invalid HTML,
> anything is possible.

I didn't follow the previous part, can you elaborate?

>
> So if |x| is appended to body with height: 0, then there's no reflow?

If it is statically positioned, then there is certainly a reflow, but
it won't result in any visible changes (perhaps browsers will be smart
enough to skip it?)

> What about if it has a width?

Well, if the width is wider than the viewport you would get an even
worse effect (a flash of a horizontal scrollbar.) Unless you (or some
user style sheet) explicitly assign a width, you don't have to worry
about it. For safety you could set the width to 0 as well (then only !
important rules would have the potential to cause a problem.)

[snip]

dhtml

unread,
Feb 20, 2008, 2:40:56 AM2/20/08
to
David Mark wrote:
> On Feb 19, 3:40 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
> > On Feb 19, 2:41 am, David Mark <dmark.cins...@gmail.com> wrote:
> >
> > > On Feb 19, 4:15 am, dhtml <dhtmlkitc...@gmail.com> wrote:
> >
> > > > On Feb 18, 6:51 pm, David Mark <dmark.cins...@gmail.com> wrote:
> >
> > > > > On Feb 18, 8:05 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
> >
> > > > > > On Feb 17, 9:01 pm, David Mark <dmark.cins...@gmail.com> wrote:
> >
> > > > > > On Feb 17, 9:01 pm, David Mark <dmark.cins...@gmail.com> wrote:
> >
> > > > > > > On Feb 17, 5:09 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
<snip>

> > > > My Definition:


> > > > offsetParent - a containing block that is offset by margin or left/top
> > > > values.

<snip>

> > A TD, TR, or TBODY that does not have a positioned ancestor should use
> > its TABLE.

<snip>

correction:
A TD, TR, or TBODY that does not have a positioned ancestor between it
and it's table uses its TABLE as offsetParent

(so <tr| tbody style="position: relative"> makes the TR an
offsetParent)

<snip about xul>


> > <snip about reused coords>

> > I should probably worry about that when I get to it, and it probably
>
> That's my strategy for high-level UI components like scrolling lists
> with draggable items. I need to make sure the foundation is sound
> before considering such things. I do plan to port my popup menus to
> use the re-packaged API soon after the Beta release, partly as a
> simple example and partly because I need them for other things I am
> doing.


> > wouldn't be hard enough to optimize to the point that reusing coords
> > was pointless.
>
> Probably.

<snip about iframe testing>

> > > > Why [not] just use ownerDocument?


> >
> > > Because it can't be assumed to be there. The fallback branch isn't
> > > too involved.
> >
> > The only time I could think is if it's in abstract view.
>
> I was referring to ancient browsers. Can you elaborate on your point?

document.createDocument() is the only thing I could think about where
there ight not be an ownerDocument. I don't use that, so I don't know.

<snip>

> > compatMode = BackCompat, document rendered IE quirls => ditto
>
> Why would this one fail? BackCompat => IE quirks mode => body has the
> chrome border.

You're right. But the other 2 fail.

> > compatMode = BackCompat, document rendered Moz quirls => ditto
>
> We'll have to wait and see what Moz does with getBoundingClientRect
> and the chrome borders quirk.

Mozilla generally considers the viewport to be the ICB, but they've
made all sorts of special cases like
document.documentElement.clientHeight - which returns the ICB's
height, not what would be the height of the documentElement.

Firebug:
getComputedStyle(document.documentElement,'').height;
document.documentElement.clientHeight

For any other element without scrollbars, those two would be equal.
HTML does not, in mozilla, have scrollbars, the window does, but then
they sort of made HTML work like it does in IE (partially).

[snip]

> It can still be part of various tests, just not the only test. That
> is how I have always treated it. If you test for "CSS" instead of
> "BackCompat", you at least know that the HTML element is rendered. It
> is when it is "BackCompat" or undefined that there is an ambiguity. I
> just checked my code and it looks like I can lose it altogether.

I'm going to try to stay away from it.

> > // True only in IE5, or IE6+ quirks mode.
> > var IS_BODY_ACTING_ROOT = documentElement &&
> > documentElement.clientWidth === 0;

<snip>

> Thanks. I had one (multiple) object inference and now there are
> none! Good thing too as it was a really ugly one.

cool.

> > This seems to be true only in IE5, or IE6+ in quirks mode. I don'

??

<snip about my incomplete example>

> What does the computed border width evaluate to? I suppose it doesn't
> matter much as I use clientLeft/Top when available, which are always
> going to be rounded in whatever way the browser sees fit. Oh well,
> none of this is going to be perfect for every possible layout.

The border width of em gets based on the fontSize, but gets rounded.

> > When using larger numbers for font size, it becomes apparent that
> > there's also some internal miscalcuation. The numbers aren't off by 1.
> > They're off by a lot.
>
> I see.
>
> >
> > When cumulatively adding clientLeft/Top the rounded pixelValues are
> > added up, resulting in a much more skewed result.
>
> This sounds like a good case for using gCS in the offset position
> function, ignoring clientLeft/Top. I think I will do that.

That is true.

[snip about IE requiring 100 based fontWeights]

> Did you mean fontWeight? And I did not know you could have non-
> integer zIndex values. I can't imagine a use for them though.

In doing animation transitions, just use floats, but I guess it's nota
problem anyway.

> > > Here's a really weird one. I have a "grow" effect that can optionally
> > > size the font of the element. Using my em-based layout (which was my
> > > first stab at aligning to a baseline grid), I found that setting
> > > inline font sizes to their cascaded or computed values would make the
> > > fonts change in size (which makes no sense to me) and this only
> > > happened at certain text size settings (e.g. larger, smaller,
> > > smallest, but not medium.) However, if I set the inline font size
> > > style to what I know is the cascaded value before I run the animation,
> > > then all is well (the fonts have already jumped in size.)
> >
> > Try putting what you know to be cascade in the style attribute.
>
> That's what I do (in IE.)
>
> >
> > Try inspecting the currentStyle (if this is IE we're talking a
>
> The issue I mentioned is present in most browsers.

> Has Google mangled your post here?

Yeah, goddam WTF keeps happening to my post?

It's like verizon just invaded Safari.

Can you hear me now?

j/k

The quotes seem to trail off. I
> would expect currentStyle to stay the same, but in this case I imagine
> it does not (at least at certain font size settings.) Now why on
> earth would that be? And BTW, ever test any of this stuff with zoom
> enabled in IE7? That feature is so buggy that I don't really care
> about it, but I suspect it will amplify weird cases like this.
>
> >
> > That is the
> >

Again WTF? See, I knew it. I sometimes get Gmail or groups (only once
in groups) chopping off the last half of the message on a dropped wifi
connection in Safari. The chopping mid line I cannot explain. I don't
know how that would be possible. I can't imagine I had that many edit
mistakes. 1 or two, but it's three so far.


> > > one strange workaround I had to implement in all of the animation
> > > tests. I still don't understand what the deal was with that (and
> > > don't really care.) I suspect my CSS is just too convoluted, but the
> > > baseline grid does work well in all of the browsers I have tested.
> > > What Webkit browser do you test with? Windows Safari Beta?
> >
> > Yes, and also mac Safari 2 and Webkit recent build.
>
> Well, I'll try your unit tests in IE5.x and perhaps you can try mine
> in the Mac Safari browsers (I have heard hey differ wildly from the
> Windows Beta.)

It's not actually here. I mean, I have a mac, but not here. Last time
I checked, the offsetStuff worked the same in 2. 2's got more bugs
than 3. Send me a link. It's automated, right?

> > That> browser still has some serious issues.
> >
> > It's fast. It's a lot more standards than Opera.
>
> It is indeed fast at DOM traversal and perhaps a tie with IE for
> smooth animations. It seems to take a bit longer to load (pages and
> itself) than other browsers.

Safari kicks IE's ass in animation.

> I like the font rendering too.

The soft side of David Mark.

j/k.

:D

> > <snip>
> >
> > > I probably will too. The lesson is that nothing is going to be 100%
> > > perfect for all cases in all browsers. I figure that the best I can
> > > shoot for is 99%. It seems to me that the currently popular libraries
> > > take a stance like "three out of four ain't bad."
> >
> > There are cases of working, not working, or somewhere in between. It
> > works, but it's buggy/returns inaccurate results. I guess there's a
> > degree of acceptibility in "not quite working" that I'm not
> > considering. I'll try to just take what I know about degradation and
> > old browser bugs and try not to cause problems. I don't like thinking
> > about that too much; though. Having conditions for browsers I can't
> > test in complicates the code.
>
> That's always a concern.

Graceful degradation is a very good consideration, if it works. If it
can't be tested... well, if I'm not testing in a browser, it's got a
good chance of failing, and possibly in a totally different and stupid
way. It's those seemingly well-intentioned ideas, like adding a
remove() method to compliment add(). You're intuition/subconcious does
not give it as much importance. These cases are where I worry. if it
does happen, what will it do?

That's why I have dumb tests for things like Assert.isTypeof("string",
el.toString()).

I remember staying at work late one night because toString didn't work
on a certain library -- threw an error, actually. I didn't call
toString, but other code in the library did.

The author probably just put in toString for debugging but then
changed the design. Being javascript, there was no compile-time error.
The design was also a contributing factor in that one. A 3-4 long
inheritance chain, which was nicely diagrammed on the libary's website
in *reverse* UML (the graphical arrows -- which were quite attractive
-- were all backwards). Anyway, the code worked fine and went to
production. Then toString didn't work in my case. The author of the
script had to leave early, but I stayed late, trying to figure out
what was wrong.

So the point is that toString was not mission critical, was not
tested, and actually caused a problem (related to a complicated
design). I'm not saying toString is bad.

I don't have a good partial degradation strategy. If i could test more
browsers, I degrade to acceptable levels. This takes a lot more time,
from what I remember about the old version 4 browsers, it was a lot of
work to do small things. It is definitely the right approach and
attitude for web scripting.

> > <snip>
> >
> > > > > > getComputedStyle is (or should be) a pixel value.
> >
> > > > > It is indeed.
> >
> > > > Webkit returns 'auto' when margin: auto and left is undeclared.http://www.dhtmlkitchen.com/test/bug/getComputedStyle.html
> >
> > > My gCS wrapper will never return "auto", but instead returns null.
> >
> > I would probably return an empty string. to avoid having to write:
> >
> > if(val != null && val != "")
>
> But when would the computed style ever be an empty string? I know
> cases where it can be null (e.g. display:none makes all of them null
> in some browsers), but an empty string?

A lot of times.

Safari returns '' for clip
Mozilla does too, for any shorthand prop, like border. Mozilla at
first only implemented a few styles.

if(s != null && s.split(" "))

You could turn it around and use /\s/.exec(s), I suppose.

I like String methods to return strings. I like my code to be safe
enough for me to use on a bad day, and hopefully safe enough for
others, too.

Its more annoying with arrays.

var m = s.match(exp);
if(m && m[0])
v = m[0];

I would rather have had match return an empty array.

Same thing with request.getCookies() (Java).

Josh Bloch is big on this. If you haven't checked out Effective Java,
it's not too heavy reading. Good stuff.

> > var TABLE = /^h/.test(documentElement.tagName) ? "table" : "TABLE";

With YUI compressor TABLE will be convered to a 1 letter symbol. This
will reduce file size. Of course the best benefit is that for the
entire life of the function, it only creates one "TABLE" string which
is needed many times. This reduces memory. fewer temp string objects.
fewer function calls.

About build... When you've got time, I'd like to ask you about YUI
compressor. (we can kill this thread) I'd really like to hear your
build process (in a new thread, of course).

> > Shorter.
> >
> > <snip about computed styles>
> >
> > > > > > Opera returns wrong results for |left| when the element has a border?
> > > > > > I can't reproduce that.
> >
> > > > > It does in my copy of Opera 9 (I forget which revision.) I had to put
> > > > > a quirk test in for that. Same for height/width. They were always
> > > > > off by the width of the border(s).
> >
> > > > I've got Opera 9.25 and it doesn't do that.
> >
> > > That means they fixed it and my code will skip the workaround in that
> > > and subsequent versions. Isn't feature testing wonderful?
> >
> > Doesn't mean they fixed a bug. It means you've got a workaround for
> > something that I can't reproduce.
>
> Trust me, you'd be able to reproduce this easily enough. Just get the
> computed height/width style of any element with a border. When this
> bug is present, the border is included in the dimensions (!) From
> looking at my test for this, they don't have to be statically
> positioned (as previously reported.) As for the similar left/top
> issue, from looking at my test, it is either not exactly as I
> remembered (and reported) it or I botched the test code when I
> transplanted it into the library (doubtful.) I will have to re-test
> that case.

wow that blows. I can repro that. Opera.

<snip>

> My test code is currently testing whether the border width of a
> positioned parent is included (which isn't what I remembered it
> doing.) Could be the same issue. Regardless, I have a bullet-proof
> way of fixing problems with computed dimensions and positions that
> also accounts for box model differences.

That feature detection is very clean. Where I have comments, you have
a variable that points to the execution of an inline function. I will
eventually adopt this style into my code.

> > Those two divs at the top? getPropertyValue('left') should be '0'.
> > Opera returns '8px', which comes from the body's margin.
>
> That will happen with borders too. Apparently my test is correct, but
> I just remembered the bug wrong. I typically try to forget bugs once
> a feature test has been proven to work around them. As an aside, I
> wonder if anyone out there reading this thread still thinks that
> browser sniffing is either necessary or a good idea.

I used to use it. I thought it was a bad idea, but still used it
anyway.

I wonder if everyone thinks I'm crazy for trying to get an element's
position. Sounds a lot simpler than it is.

Maybe.


> > Maybe a complication of trying to implement the CSSOM views spec.
>
> The what?

CSSOM Views. That's AVK's offsetParent spec.

<snip>

> > When I think about it, I'm a little worried about the tree structure
> > being wrong.
> >
> > <body>
> > <div>
> > <p>..parsing...
> > appendChild called -> <div/>
>
> You lost me there.

1. polling for document.body every 60ms
2. document.body is evaluated as true in our poll, but after some of
it's content has been parsed.
3. call body.appendChild
4. what will IE do?

I don't expect you to know the answer. But it's something I'm afraid
of.

Garrett

David Mark

unread,
Feb 20, 2008, 4:48:32 AM2/20/08
to
On Feb 20, 2:40 am, dhtml <dhtmlkitc...@gmail.com> wrote:
> David Mark wrote:
> > On Feb 19, 3:40 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
> > > On Feb 19, 2:41 am, David Mark <dmark.cins...@gmail.com> wrote:
>
> > > > On Feb 19, 4:15 am, dhtml <dhtmlkitc...@gmail.com> wrote:
>
> > > > > On Feb 18, 6:51 pm, David Mark <dmark.cins...@gmail.com> wrote:
>
> > > > > > On Feb 18, 8:05 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
>
> > > > > > > On Feb 17, 9:01 pm, David Mark <dmark.cins...@gmail.com> wrote:
>
> > > > > > > On Feb 17, 9:01 pm, David Mark <dmark.cins...@gmail.com> wrote:
>
> > > > > > > > On Feb 17, 5:09 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
>
> <snip>
>
> > > > > My Definition:
> > > > > offsetParent - a containing block that is offset by margin or left/top
> > > > > values.
>
> <snip>
>
> > > A TD, TR, or TBODY that does not have a positioned ancestor should use
> > > its TABLE.
>
> <snip>
>
> correction:
> A TD, TR, or TBODY that does not have a positioned ancestor between it
> and it's table uses its TABLE as offsetParent
>
> (so <tr| tbody style="position: relative"> makes the TR an
> offsetParent)

Right.

>
> <snip about xul>
>
> > > <snip about reused coords>
> > > I should probably worry about that when I get to it, and it probably
>
> > That's my strategy for high-level UI components like scrolling lists
> > with draggable items. I need to make sure the foundation is sound
> > before considering such things. I do plan to port my popup menus to
> > use the re-packaged API soon after the Beta release, partly as a
> > simple example and partly because I need them for other things I am
> > doing.
> > > wouldn't be hard enough to optimize to the point that reusing coords
> > > was pointless.
>
> > Probably.
>
> <snip about iframe testing>
>
> > > > > Why [not] just use ownerDocument?
>
> > > > Because it can't be assumed to be there. The fallback branch isn't
> > > > too involved.
>
> > > The only time I could think is if it's in abstract view.
>
> > I was referring to ancient browsers. Can you elaborate on your point?
>
> document.createDocument() is the only thing I could think about where
> there ight not be an ownerDocument. I don't use that, so I don't know.

For that case, getElementDocument returns null, indicating that the
element is not part of any document. I wouldn't expect an application
to call that function for such an element, but it won't hurt anything.

>
> <snip>
>
> > > compatMode = BackCompat, document rendered IE quirls => ditto
>
> > Why would this one fail? BackCompat => IE quirks mode => body has the
> > chrome border.
>
> You're right. But the other 2 fail.

I thought that must have been a typo.

>
> > > compatMode = BackCompat, document rendered Moz quirls => ditto
>
> > We'll have to wait and see what Moz does with getBoundingClientRect
> > and the chrome borders quirk.
>
> Mozilla generally considers the viewport to be the ICB, but they've
> made all sorts of special cases like
> document.documentElement.clientHeight - which returns the ICB's
> height, not what would be the height of the documentElement.

WHen the HTML element (or body element in quirks mode) has borders or
margins (a really odd case of course), measuring the inner viewport
area using the clientWidth/Height properties requires several feature
tests to work cross-browser. I don't remember which browsers required
which workarounds (and happily I don't have to!)

>
> Firebug:
> getComputedStyle(document.documentElement,'').height;
> document.documentElement.clientHeight
>
> For any other element without scrollbars, those two would be equal.

With the standard box model, yes.

> HTML does not, in mozilla, have scrollbars, the window does, but then
> they sort of made HTML work like it does in IE (partially).

Yes. Each layout engine has its own idea about what constitutes the
viewport. Getting a working viewport measurement for standards and
quirks mode was hell on earth. Opera 9 (and perhaps other versions)
has the worst quirk (bug?) of all in that the clientHeight of the
documentElement is a figure more akin to the scrollHeight (which is
ridiculous.) Oddly enough, clientWidth works as expected. (!)

>
> [snip]
>
> > It can still be part of various tests, just not the only test. That
> > is how I have always treated it. If you test for "CSS" instead of
> > "BackCompat", you at least know that the HTML element is rendered. It
> > is when it is "BackCompat" or undefined that there is an ambiguity. I
> > just checked my code and it looks like I can lose it altogether.
>
> I'm going to try to stay away from it.

I am going to remove all references to it when I get a chance. I've
got maybe three functions that use it and it is mostly a source of
convolution.

>
> > > // True only in IE5, or IE6+ quirks mode.
> > > var IS_BODY_ACTING_ROOT = documentElement &&
> > > documentElement.clientWidth === 0;
>
> <snip>
>
> > Thanks. I had one (multiple) object inference and now there are
> > none! Good thing too as it was a really ugly one.
>
> cool.
>
> > > This seems to be true only in IE5, or IE6+ in quirks mode. I don'
>
> ??
>
> <snip about my incomplete example>
>
> > What does the computed border width evaluate to? I suppose it doesn't
> > matter much as I use clientLeft/Top when available, which are always
> > going to be rounded in whatever way the browser sees fit. Oh well,
> > none of this is going to be perfect for every possible layout.
>
> The border width of em gets based on the fontSize, but gets rounded.

Oh well.

>
> > > When using larger numbers for font size, it becomes apparent that
> > > there's also some internal miscalcuation. The numbers aren't off by 1.
> > > They're off by a lot.
>
> > I see.
>
> > > When cumulatively adding clientLeft/Top the rounded pixelValues are
> > > added up, resulting in a much more skewed result.
>
> > This sounds like a good case for using gCS in the offset position
> > function, ignoring clientLeft/Top. I think I will do that.
>
> That is true.
>
> [snip about IE requiring 100 based fontWeights]
>
> > Did you mean fontWeight? And I did not know you could have non-
> > integer zIndex values. I can't imagine a use for them though.
>
> In doing animation transitions, just use floats, but I guess it's nota
> problem anyway.

I don't follow you there. Regardless, I have no control over what
sort of element is transitioned. I endeavored to support everything
for all of the effects. For instance, using the slide effect (the one
that Prototype fakes by requiring an extra container element),
positions a static element in its initialization.

>
> > > > Here's a really weird one. I have a "grow" effect that can optionally
> > > > size the font of the element. Using my em-based layout (which was my
> > > > first stab at aligning to a baseline grid), I found that setting
> > > > inline font sizes to their cascaded or computed values would make the
> > > > fonts change in size (which makes no sense to me) and this only
> > > > happened at certain text size settings (e.g. larger, smaller,
> > > > smallest, but not medium.) However, if I set the inline font size
> > > > style to what I know is the cascaded value before I run the animation,
> > > > then all is well (the fonts have already jumped in size.)
>
> > > Try putting what you know to be cascade in the style attribute.
>
> > That's what I do (in IE.)
>
> > > Try inspecting the currentStyle (if this is IE we're talking a
>
> > The issue I mentioned is present in most browsers.
> > Has Google mangled your post here?
>
> Yeah, goddam WTF keeps happening to my post?

No idea.

>
> It's like verizon just invaded Safari.
>
> Can you hear me now?
>

Good!

> j/k
>
> The quotes seem to trail off. I
>
> > would expect currentStyle to stay the same, but in this case I imagine
> > it does not (at least at certain font size settings.) Now why on
> > earth would that be? And BTW, ever test any of this stuff with zoom
> > enabled in IE7? That feature is so buggy that I don't really care
> > about it, but I suspect it will amplify weird cases like this.
>
> > > That is the
>
> Again WTF? See, I knew it. I sometimes get Gmail or groups (only once
> in groups) chopping off the last half of the message on a dropped wifi
> connection in Safari. The chopping mid line I cannot explain. I don't
> know how that would be possible. I can't imagine I had that many edit
> mistakes. 1 or two, but it's three so far.

I've never seen such a thing. Clearly something went horribly wrong
when you posted this message.

>
> > > > one strange workaround I had to implement in all of the animation
> > > > tests. I still don't understand what the deal was with that (and
> > > > don't really care.) I suspect my CSS is just too convoluted, but the
> > > > baseline grid does work well in all of the browsers I have tested.
> > > > What Webkit browser do you test with? Windows Safari Beta?
>
> > > Yes, and also mac Safari 2 and Webkit recent build.
>
> > Well, I'll try your unit tests in IE5.x and perhaps you can try mine
> > in the Mac Safari browsers (I have heard hey differ wildly from the
> > Windows Beta.)
>
> It's not actually here. I mean, I have a mac, but not here. Last time
> I checked, the offsetStuff worked the same in 2. 2's got more bugs
> than 3. Send me a link. It's automated, right?

The link I sent you before is the only version online. It does not
have test page has no cases for verification of offset positioning.
And none of my testing is automated at this time. You click buttons
and observe the results. I realize this is not ideal, but it is what
I have always done. I am sure I will add some more in-depth automated
testing in the future.

The separate CSS selector test page is a hacked version of the
MooTools "SlickSpeed" test page and is semi-automatic (you click one
button to run all of the tests.) Check it out when you a get a
chance. Testing here, mine wins every time overall and wins most of
the individual tests as well. As an aside, Prototype is by far the
slowest for virtually every test. I am sure if I add Ext to the mix I
will lose in browsers that don't support XPath (and Safari 3 where I
disable XPath due to a failed feature test.) Adding the Function
constructor trick that Peter demonstrated in the tabbed pane sample
will likely rectify that.

>
> > > That> browser still has some serious issues.
>
> > > It's fast. It's a lot more standards than Opera.
>
> > It is indeed fast at DOM traversal and perhaps a tie with IE for
> > smooth animations. It seems to take a bit longer to load (pages and
> > itself) than other browsers.
>
> Safari kicks IE's ass in animation.

I suppose it depends on a number of factors. In my testing, they
appear to be of similar capabilities.

FF is the worst. And what is the deal with that stupid blink when
setting opacity to 1? I had heard that FF 2 fixed this. Not here (at
least not in my test cases.) Setting opacity to .9999 and then
setting it to 1 (even when using a timeout that fires seconds later)
causes a blink. To get around this, I simply animate to .9999 and
stop (a workaround that I am not happy with.) There is an indirect
test for this in the Beta as I had to set one widget to 100% opacity
to work around some other FF rendering weirdness involving its use
with unrelated effects. I'll be interested to hear if others see the
blink.

Opera's quality is somewhere in between IE and FF.

>
> > I like the font rendering too.
>
> The soft side of David Mark.
>
> j/k.
>
> :D

LOL. I like pretty fonts as much as the next guy. But seriously, my
primary monitor is an ancient 60" TV (S-VHS connection) and Safari's
rendering is much easier on the eyes.

>
> > > <snip>
>
> > > > I probably will too. The lesson is that nothing is going to be 100%
> > > > perfect for all cases in all browsers. I figure that the best I can
> > > > shoot for is 99%. It seems to me that the currently popular libraries
> > > > take a stance like "three out of four ain't bad."
>
> > > There are cases of working, not working, or somewhere in between. It
> > > works, but it's buggy/returns inaccurate results. I guess there's a
> > > degree of acceptibility in "not quite working" that I'm not
> > > considering. I'll try to just take what I know about degradation and
> > > old browser bugs and try not to cause problems. I don't like thinking
> > > about that too much; though. Having conditions for browsers I can't
> > > test in complicates the code.
>
> > That's always a concern.
>
> Graceful degradation is a very good consideration, if it works. If it
> can't be tested... well, if I'm not testing in a browser, it's got a
> good chance of failing, and possibly in a totally different and stupid
> way. It's those seemingly well-intentioned ideas, like adding a
> remove() method to compliment add(). You're intuition/subconcious does
> not give it as much importance. These cases are where I worry. if it
> does happen, what will it do?

The unknown will always have to be considered when planning for
graceful degradation.

>
> That's why I have dumb tests for things like Assert.isTypeof("string",
> el.toString()).
>
> I remember staying at work late one night because toString didn't work
> on a certain library -- threw an error, actually. I didn't call
> toString, but other code in the library did.

Didn't work in what way?

>
> The author probably just put in toString for debugging but then
> changed the design. Being javascript, there was no compile-time error.
> The design was also a contributing factor in that one. A 3-4 long
> inheritance chain, which was nicely diagrammed on the libary's website
> in *reverse* UML (the graphical arrows -- which were quite attractive
> -- were all backwards). Anyway, the code worked fine and went to
> production. Then toString didn't work in my case. The author of the
> script had to leave early, but I stayed late, trying to figure out
> what was wrong.
>
> So the point is that toString was not mission critical, was not
> tested, and actually caused a problem (related to a complicated
> design). I'm not saying toString is bad.

I didn't follow that, but I don't use toString on elements anyway.

>
> I don't have a good partial degradation strategy. If i could test more
> browsers, I degrade to acceptable levels. This takes a lot more time,
> from what I remember about the old version 4 browsers, it was a lot of
> work to do small things. It is definitely the right approach and
> attitude for web scripting.
>
> > > <snip>
>
> > > > > > > getComputedStyle is (or should be) a pixel value.
>
> > > > > > It is indeed.
>
> > > > > Webkit returns 'auto' when margin: auto and left is undeclared.http://www.dhtmlkitchen.com/test/bug/getComputedStyle.html
>
> > > > My gCS wrapper will never return "auto", but instead returns null.
>
> > > I would probably return an empty string. to avoid having to write:
>
> > > if(val != null && val != "")
>
> > But when would the computed style ever be an empty string? I know
> > cases where it can be null (e.g. display:none makes all of them null
> > in some browsers), but an empty string?
>
> A lot of times.

LOL. I was blinded by my own abstractions. I convert them to null.

>
> Safari returns '' for clip

That makes sense as clip is shorthand.

> Mozilla does too, for any shorthand prop, like border. Mozilla at
> first only implemented a few styles.

Computed shorthand styles sounds like a contradiction in terms to me.
I wouldn't rely on being able to query styles like that.

>
> if(s != null && s.split(" "))
>
> You could turn it around and use /\s/.exec(s), I suppose.

What are you doing there?

>
> I like String methods to return strings. I like my code to be safe
> enough for me to use on a bad day, and hopefully safe enough for
> others, too.

Generally, I prefer that they return strings only for valid results
and null otherwise. Some functions are allowed to return empty
strings and some are not. The gCS wrapper is one that is not.

>
> Its more annoying with arrays.
>
> var m = s.match(exp);
> if(m && m[0])
> v = m[0];
>
> I would rather have had match return an empty array.

I don't follow what you are doing with these last two examples.

>
> Same thing with request.getCookies() (Java).

I don't concern myself with Java. I have enough headaches with
browser scripting. I haven't looked at my cookie code in ages, but
IIRC, it returns null only if the cookie does not exist. An empty
string would indicate an empty (no calorie) cookie. Granted, most
applications likely wouldn't care one way or the other.

Speaking of those, it was a pain, but I have crumbs working in a way
that is compatible with ASP's "keyed" cookies. I find that very
useful.

>
> Josh Bloch is big on this. If you haven't checked out Effective Java,
> it's not too heavy reading. Good stuff.

Java doesn't exist as far as I am concerned.

>
> > > var TABLE = /^h/.test(documentElement.tagName) ? "table" : "TABLE";
>
> With YUI compressor TABLE will be convered to a 1 letter symbol. This
> will reduce file size. Of course the best benefit is that for the

Yes, I designed to leverage that. 330K+ for the full build (with
fairly sparse comments) minifies to something like 110K. Just to
compare it to other libraries, I GZIP'ed the resulting file and it is
almost exactly 40K. Granted, it would take one hellacious application
to require the full build.

> entire life of the function, it only creates one "TABLE" string which
> is needed many times. This reduces memory. fewer temp string objects.
> fewer function calls.

Yes, I like that trick. I might have to copy it.

>
> About build... When you've got time, I'd like to ask you about YUI
> compressor. (we can kill this thread) I'd really like to hear your
> build process (in a new thread, of course).

Okay. In a nutshell, the YUI compressor is outstanding. It has never
let me down.

>
> > > Shorter.
>
> > > <snip about computed styles>
>
> > > > > > > Opera returns wrong results for |left| when the element has a border?
> > > > > > > I can't reproduce that.
>
> > > > > > It does in my copy of Opera 9 (I forget which revision.) I had to put
> > > > > > a quirk test in for that. Same for height/width. They were always
> > > > > > off by the width of the border(s).
>
> > > > > I've got Opera 9.25 and it doesn't do that.
>
> > > > That means they fixed it and my code will skip the workaround in that
> > > > and subsequent versions. Isn't feature testing wonderful?
>
> > > Doesn't mean they fixed a bug. It means you've got a workaround for
> > > something that I can't reproduce.
>
> > Trust me, you'd be able to reproduce this easily enough. Just get the
> > computed height/width style of any element with a border. When this
> > bug is present, the border is included in the dimensions (!) From
> > looking at my test for this, they don't have to be statically
> > positioned (as previously reported.) As for the similar left/top
> > issue, from looking at my test, it is either not exactly as I
> > remembered (and reported) it or I botched the test code when I
> > transplanted it into the library (doubtful.) I will have to re-test
> > that case.
>
> wow that blows. I can repro that. Opera.

Doesn't it? As you can imagine, the feature test is simple.

>
> <snip>
>
> > My test code is currently testing whether the border width of a
> > positioned parent is included (which isn't what I remembered it
> > doing.) Could be the same issue. Regardless, I have a bullet-proof
> > way of fixing problems with computed dimensions and positions that
> > also accounts for box model differences.
>
> That feature detection is very clean. Where I have comments, you have
> a variable that points to the execution of an inline function. I will
> eventually adopt this style into my code.

Thanks. I copied that pattern from Richard Cornford's sample
scripts. AFAIK, he invented the "one-off" feature test. My whole
library is based on it, so I will certainly give him an
acknowledgement (if he wants one.)

>
> > > Those two divs at the top? getPropertyValue('left') should be '0'.
> > > Opera returns '8px', which comes from the body's margin.
>
> > That will happen with borders too. Apparently my test is correct, but
> > I just remembered the bug wrong. I typically try to forget bugs once
> > a feature test has been proven to work around them. As an aside, I
> > wonder if anyone out there reading this thread still thinks that
> > browser sniffing is either necessary or a good idea.
>
> I used to use it. I thought it was a bad idea, but still used it
> anyway.

I used to use it for virtually everything. Who didn't in the 90's? I
even did server side sniffing. What is unthinkable is that people
continue to do it in 2008. I've seen blog posts recently that
advocated server side sniffing for dealing with the XHTML MIME type
issue. (!)

>
> I wonder if everyone thinks I'm crazy for trying to get an element's
> position. Sounds a lot simpler than it is.
>
> Maybe.

It is needed for some applications. Personally, I try to avoid it at
all costs.

>
> > > Maybe a complication of trying to implement the CSSOM views spec.
>
> > The what?
>
> CSSOM Views. That's AVK's offsetParent spec.

Oh. That thing.

>
> <snip>
>
> > > When I think about it, I'm a little worried about the tree structure
> > > being wrong.
>
> > > <body>
> > > <div>
> > > <p>..parsing...
> > > appendChild called -> <div/>
>
> > You lost me there.
>
> 1. polling for document.body every 60ms
> 2. document.body is evaluated as true in our poll, but after some of
> it's content has been parsed.
> 3. call body.appendChild
> 4. what will IE do?

IE6 will throw the dreaded "operation aborted" error AFAIK. You
really need to change that. See the attachDocumentReadyListener
ticket in CWR.

>
> I don't expect you to know the answer. But it's something I'm afraid
> of.

Be very afraid. There's no catastrophe (short of ill-formed XHTML)
that can compare to "operation aborted."

BTW, do you know in what way gBOF fails in embedded Mozilla-based
browsers? An exception? If so, I need to get rid of it ASAP.

dhtml

unread,
Feb 21, 2008, 5:35:56 AM2/21/08
to
On Feb 20, 1:48 am, David Mark <dmark.cins...@gmail.com> wrote:
> On Feb 20, 2:40 am, dhtml <dhtmlkitc...@gmail.com> wrote:
>
> > David Mark wrote:
> > > On Feb 19, 3:40 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
> > > > On Feb 19, 2:41 am, David Mark <dmark.cins...@gmail.com> wrote:
>
> > > > > On Feb 19, 4:15 am, dhtml <dhtmlkitc...@gmail.com> wrote:
>
> > > > > > On Feb 18, 6:51 pm, David Mark <dmark.cins...@gmail.com> wrote:
>
> > > > > > > On Feb 18, 8:05 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
>
> > > > > > > > On Feb 17, 9:01 pm, David Mark <dmark.cins...@gmail.com> wrote:
>
> > > > > > > > On Feb 17, 9:01 pm, David Mark <dmark.cins...@gmail.com> wrote:
>
> > > > > > > > > On Feb 17, 5:09 pm, dhtml <dhtmlkitc...@gmail.com> wrote:
>
[snip about offsetParent]


[snip about rying to get the position of an element in abstract view][
[snip]


[snip about several feature tests req'd to calc the viewport width in
quirks mode]

[snip about detecting viewport dimensions]

[snip about compatMode]

>
> > <snip about my incomplete example>
>
> > > What does the computed border width evaluate to? I suppose it doesn't
> > > matter much as I use clientLeft/Top when available, which are always
> > > going to be rounded in whatever way the browser sees fit. Oh well,
> > > none of this is going to be perfect for every possible layout.
>
> > The border width of em gets based on the fontSize, but gets rounded.
>
> Oh well.

Opera seems to have problems calculating ems.

http://dhtmlkitchen.com/ape/test/tests/dom/style-f-test.html

testGetComputedStyle : function() {
var Assert = YAHOO.util.Assert;
var ArrayAssert = YAHOO.util.ArrayAssert;
var dom = APE.dom;

var testNode = document.getElementById( "testNode" );
var rule = this.data.rule;
rule.style.fontSize = "12px";
rule.style.fontFamily="fantasy";
rule.style.padding = "6em";
rule.style.height = "1000em";

var foundFontSize = dom.getStyle(testNode, "fontSize" );
var foundPadding = dom.getStyle(testNode, "paddingBottom" );
var foundHeight = dom.getStyle(testNode, "height" );

Assert.areEqual( "12px", foundFontSize );
//Assert.areEqual( (12 * 6) + "px", foundPadding );
Assert.areEqual( "12000px", foundHeight,
"height was set in em, and was either \nreturned wrong or
miscalc'd by the browser." );

},

FAIL testGetComputedStyle: height was set in em, and was either
returned wrong or miscalc'd by the browser. Expected: 12000px (string)
Actual:12144px (string)


Using currentStyle, well, it's completely f'd in Opera.
currentStyle.opacity => always 1
letterSpacing => 1, when it should be 0
currentStyle.fontSize => floor(expected) + unit.


Opera 9.25:

javascript:void(document.body.style.fontSize ='.9em');
javascript:alert(document.body.currentStyle.fontSize );

result:

"0em"

This one's really weird:
javascript:alert(document.getElementsByTagName("head")
[0].currentStyle.fontSize);

currentStyle is broken in Opera.

Opera is worse at Math than I am.

> > > > When using larger numbers for font size, it becomes apparent that
> > > > there's also some internal miscalcuation. The numbers aren't off by 1.
> > > > They're off by a lot.
>
> > > I see.
>
> > > > When cumulatively adding clientLeft/Top the rounded pixelValues are
> > > > added up, resulting in a much more skewed result.
>
> > > This sounds like a good case for using gCS in the offset position
> > > function, ignoring clientLeft/Top. I think I will do that.
>
> > That is true.
>
> > [snip about IE requiring 100 based fontWeights]
>
> > > Did you mean fontWeight? And I did not know you could have non-
> > > integer zIndex values. I can't imagine a use for them though.
>
> > In doing animation transitions, just use floats, but I guess it's nota
> > problem anyway.
>
> I don't follow you there.

floating point numbers for zIndex. I guess it's nota prob.

Regardless, I have no control over what
> sort of element is transitioned. I endeavored to support everything
> for all of the effects. For instance, using the slide effect (the one
> that Prototype fakes by requiring an extra container element),
> positions a static element in its initialization.

> > > > > Here's a really weird one. I have a "grow" effect that can optionally
> > > > > size the font of the element. Using my em-based layout (which was my
> > > > > first stab at aligning to a baseline grid), I found that setting
> > > > > inline font sizes to their cascaded or computed values would make the
> > > > > fonts change in size (which makes no sense to me) and this only
> > > > > happened at certain text size settings (e.g. larger, smaller,
> > > > > smallest, but not medium.) However, if I set the inline font size
> > > > > style to what I know is the cascaded value before I run the animation,
> > > > > then all is well (the fonts have already jumped in size.)

I did change taht example I showed you to use em for fonts. It's
probably your TV.

[snip]


>
> The separate CSS selector test page is a hacked version of the
> MooTools "SlickSpeed" test page and is semi-automatic (you click one
> button to run all of the tests.) Check it out when you a get a
> chance. Testing here, mine wins every time overall and wins most of
> the individual tests as well. As an aside, Prototype is by far the
> slowest for virtually every test. I am sure if I add Ext to the mix I
> will lose in browsers that don't support XPath (and Safari 3 where I
> disable XPath due to a failed feature test.) Adding the Function
> constructor trick that Peter demonstrated in the tabbed pane sample
> will likely rectify that.

I missed that one.

[animation]

> FF is the worst. And what is the deal with that stupid blink when
> setting opacity to 1?

I saw the blink in old 1.x, pre 1.5. I thought it got fixed. I haven't
seen it. I don't like having such workarounds either.

There's not test for "did blink".

I'd be inclined to let it just blink. This kind of browser bug is
unacceptable, and especially if it's a regression. If a browser cannot
correctly support a feature, it should not support it in a broken way.
This seems broken to me.

> LOL. I like pretty fonts as much as the next guy. But seriously, my
> primary monitor is an ancient 60" TV (S-VHS connection) and Safari's
> rendering is much easier on the eyes.

Weird.

[snip]

> > That's why I have dumb tests for things like Assert.isTypeof("string",
> > el.toString()).
>
> > I remember staying at work late one night because toString didn't work
> > on a certain library -- threw an error, actually. I didn't call
> > toString, but other code in the library did.
>
> Didn't work in what way?

They had a to string that had a ReferenceError (they changed the API)

toString : function() {
return this.noexistant.prop;
}

> > The author probably just put in toString for debugging but then
> > changed the design. Being javascript, there was no compile-time error.
> > The design was also a contributing factor in that one. A 3-4 long
> > inheritance chain, which was nicely diagrammed on the libary's website
> > in *reverse* UML (the graphical arrows -- which were quite attractive
> > -- were all backwards). Anyway, the code worked fine and went to
> > production. Then toString didn't work in my case. The author of the
> > script had to leave early, but I stayed late, trying to figure out
> > what was wrong.
>
> > So the point is that toString was not mission critical, was not
> > tested, and actually caused a problem (related to a complicated
> > design). I'm not saying toString is bad.
>
> I didn't follow that, but I don't use toString on elements anyway.


They had a toString that was broken. The problem with not testing is
it invites problems to creep in to less common execution paths.

I use toString a lot. It makes debugging easier (for me).

using String.prototype.match.

match returns an array, or null if the array would be empty.

I'd rather have an empty array than have to do a null check.

[snip]


> > About build... When you've got time, I'd like to ask you about YUI
> > compressor. (we can kill this thread) I'd really like to hear your
> > build process (in a new thread, of course).
>
> Okay. In a nutshell, the YUI compressor is outstanding. It has never
> let me down.

I'm using it, but I've got to get it hooked into ANT and automate the
process.

[snip]


> > > > <body>
> > > > <div>
> > > > <p>..parsing...
> > > > appendChild called -> <div/>
>
> > > You lost me there.
>
> > 1. polling for document.body every 60ms
> > 2. document.body is evaluated as true in our poll, but after some of
> > it's content has been parsed.
> > 3. call body.appendChild
> > 4. what will IE do?
>
> IE6 will throw the dreaded "operation aborted" error AFAIK. You
> really need to change that. See the attachDocumentReadyListener
> ticket in CWR.

Grabbing documentElement.innerHTML every 10ms seems pretty
inefficient. That's a lot of large strings. I've got a
ContentLoadAdapter.

> Be very afraid. There's no catastrophe (short of ill-formed XHTML)
> that can compare to "operation aborted."

I remember now, yeah.

> BTW, do you know in what way gBOF fails in embedded Mozilla-based
> browsers? An exception? If so, I need to get rid of it ASAP.

All I know is what I read in that bugzilla report. I would guess that
if it's available but doesn't work, it would return a Null Object (all
0's), but then, it might return null or throw an Error. You could try
a capability detection test to see if it works.

getBoxObjectFor = (function(){
// create element,
// do some assertions.
// return supported.
})();

Check the buzilla rep't to see if it throws an error or how it fails.
The reporter had strong words about not using it.

Garrett

David Mark

unread,
Feb 21, 2008, 6:26:39 AM2/21/08
to

Oh well.

>
> Using currentStyle, well, it's completely f'd in Opera.
> currentStyle.opacity => always 1
> letterSpacing => 1, when it should be 0
> currentStyle.fontSize => floor(expected) + unit.
>
> Opera 9.25:
>
> javascript:void(document.body.style.fontSize ='.9em');
> javascript:alert(document.body.currentStyle.fontSize );
>
> result:
>
> "0em"
>
> This one's really weird:
> javascript:alert(document.getElementsByTagName("head")
> [0].currentStyle.fontSize);
>
> currentStyle is broken in Opera.

Last I tested my cascaded style function in Opera, it was returning
some really strange results. My combined get style function always
tries to get the computed style first. I wasn't even aware that
currentStyle was available outside of IE until I saw that the test
buttons for that were enabled in Opera. Does it support runtimeStyle
too? I didn't even bother to create a test for that one.

And oh by the way, something is wrong with that cascaded to computed
IE hack in IE5.5. I ran into that during testing tonight.

>
> Opera is worse at Math than I am.

An odd attribute for computer software. It must be hanging out with
some of Google's processes.

>
> > > > > When using larger numbers for font size, it becomes apparent that
> > > > > there's also some internal miscalcuation. The numbers aren't off by 1.
> > > > > They're off by a lot.
>
> > > > I see.
>
> > > > > When cumulatively adding clientLeft/Top the rounded pixelValues are
> > > > > added up, resulting in a much more skewed result.
>
> > > > This sounds like a good case for using gCS in the offset position
> > > > function, ignoring clientLeft/Top.  I think I will do that.
>
> > > That is true.
>
> > > [snip about IE requiring 100 based fontWeights]
>
> > > > Did you mean fontWeight?  And I did not know you could have non-
> > > > integer zIndex values.  I can't imagine a use for them though.
>
> > > In doing animation transitions, just use floats, but I guess it's nota
> > > problem anyway.
>
> > I don't follow you there.
>
> floating point numbers for zIndex. I guess it's nota prob.

I can't conceive of an effect that would use zIndex anyway.

>
> Regardless, I have no control over what
>
> > sort of element is transitioned.  I endeavored to support everything
> > for all of the effects.  For instance, using the slide effect (the one
> > that Prototype fakes by requiring an extra container element),
> > positions a static element in its initialization.
> > > > > > Here's a really weird one.  I have a "grow" effect that can optionally
> > > > > > size the font of the element.  Using my em-based layout (which was my
> > > > > > first stab at aligning to a baseline grid), I found that setting
> > > > > > inline font sizes to their cascaded or computed values would make the
> > > > > > fonts change in size (which makes no sense to me) and this only
> > > > > > happened at certain text size settings (e.g. larger, smaller,
> > > > > > smallest, but not medium.)  However, if I set the inline font size
> > > > > > style to what I know is the cascaded value before I run the animation,
> > > > > > then all is well (the fonts have already jumped in size.)
>
> I did change taht example I showed you to use em for fonts. It's
> probably your TV.

Do you mean my video card? It is one of those crappy ATI All-in-
Wonder things. I'm on my second one of those in that box as the first
one had a meltdown (literally) and had to be shipped back for
replacement.

>
> [snip]
>
>
>
> > The separate CSS selector test page is a hacked version of the
> > MooTools "SlickSpeed" test page and is semi-automatic (you click one
> > button to run all of the tests.)  Check it out when you a get a
> > chance.  Testing here, mine wins every time overall and wins most of
> > the individual tests as well.  As an aside, Prototype is by far the
> > slowest for virtually every test.  I am sure if I add Ext to the mix I
> > will lose in browsers that don't support XPath (and Safari 3 where I
> > disable XPath due to a failed feature test.)  Adding the Function
> > constructor trick that Peter demonstrated in the tabbed pane sample
> > will likely rectify that.
>
> I missed that one.

Peter's selector query? It's in the tabbed pane thread somewhere.

>
> [animation]
>
> > FF is the worst.  And what is the deal with that stupid blink when
> > setting opacity to 1?
>
> I saw the blink in old 1.x, pre 1.5. I thought it got fixed. I haven't

I thought they did too. I'm not sure what is going on with that, but
it happens on two different test boxes. It isn't just during
animations either. Just setting opacity to 1 and then something else
(or vice versa) triggers it. It might be a quirk of my aforementioned
torturous style rules as I checked an old page that had a fade effect
and it didn't do it. That one used a similar but less efficient
setOpacity function (set all three variations of the style every
time.) I really need to run some more tests to compare the two
functions in FF.

> seen it. I don't like having such workarounds either.
>
> There's not test for "did blink".

Right.

>
> I'd be inclined to let it just blink. This kind of browser bug is

If it turns out that the majority of people who try the test page are
not seeing the blink (it is impossible to miss), I might go that
route.

> unacceptable, and especially if it's a regression. If a browser cannot
> correctly support a feature, it should not support it in a broken way.
> This seems broken to me.

Certainly.

>
> > LOL.  I like pretty fonts as much as the next guy.  But seriously, my
> > primary monitor is an ancient 60" TV (S-VHS connection) and Safari's
> > rendering is much easier on the eyes.
>
> Weird.

Not really. I hate hunching over a keyboard at a desk. I have a
wireless keyboard and mouse so I can sit on the couch in the den. The
PC is basically part of my entertainment system. The secondary
monitor is a touch screen mounted in the wall next to it. I typically
drag Winamp and my "soft phone" to that one. I've got some home
automation software on that box too, so I can use the touch screen to
control and monitor various things in the house too.

>
> [snip]
>
> > > That's why I have dumb tests for things like Assert.isTypeof("string",
> > > el.toString()).
>
> > > I remember staying at work late one night because toString didn't work
> > > on a certain library -- threw an error, actually. I didn't call
> > > toString, but other code in the library did.
>

[snip]

>
> > IE6 will throw the dreaded "operation aborted" error AFAIK.  You
> > really need to change that.  See the attachDocumentReadyListener
> > ticket in CWR.
>
> Grabbing documentElement.innerHTML every 10ms seems pretty
> inefficient. That's a lot of large strings. I've got a
> ContentLoadAdapter.

Sounds like a much better idea.

>
> > Be very afraid.  There's no catastrophe (short of ill-formed XHTML)
> > that can compare to "operation aborted."
>
> I remember now, yeah.
>
> > BTW, do you know in what way gBOF fails in embedded Mozilla-based
> > browsers?  An exception?  If so, I need to get rid of it ASAP.
>
> All I know is what I read in that bugzilla report. I would guess that
> if it's available but doesn't work, it would return a Null Object (all
> 0's), but then, it might return null or throw an Error. You could try
> a capability detection test to see if it works.
>
> getBoxObjectFor = (function(){
> // create element,
> // do some assertions.
> // return supported.
>
> })();

I am guarding against a null return currently, but plan to pull the
method completely when I get a chance. If the authors of FF say it is
a bad idea to use it, I believe them.

>
> Check the buzilla rep't to see if it throws an error or how it fails.
> The reporter had strong words about not using it.
>

The documents I read didn't say how it fails.

0 new messages