Anne van Kesteren

Reverse engineering offsetLeft, offsetTop and offsetParent

Some features in Internet Explorer are quite popular and are for that reason reverse engineered by other browser vendors. All very well. I decided to spend some time on reverse engineering offsetLeft, offsetTop and offsetParent (demonstrations available, preliminary specification available). This is all fun and works quite well, until you realize it’s not a simple problem. Things go as far as breaking with CSS 2.1 which is not really an option. Lets take an example which is easy to follow and shows some of the weirdness that has most likely to do with having layout in some way.

You have an outer div with position:relative; border:1px solid and an inner div with position:static; margin:10px. In this simple case the offsetLeft and offsetTop attributes of the inner div are 11 and offsetParent is the outer div. (So you calculate from border edge to margin edge as the specification (currently) states.)

Now you set height:100px on the outer div. In this “simple case” the offsetLeft and offsetTop attributes are 10 and offsetParent is still the same. We don’t want both, which one do you like?

More complicated examples show how a simple height:100px (can probably have other values as well) can change the way collapsing margins work and therefore the values of offsetLeft and offsetTop. It’s crazy. Of course, given the “march for standards” at Microsoft they will at some point encounter these problems too and I hope this can be solved within the W3C Web APIs Working Group together with them at some point. Or perhaps the CSS WG wants to revise the box model? :-)

Comments

  1. The inner div doesn't move when you do that?

    And what about the offsetLeft and offsetTop of the outer div? Do they increase by one?

    Posted by Sjoerd Visscher at

  2. Not sure about the first, I believe not. The outer div has still the same values.

    Posted by Anne at

  3. Those are clearly bugs in IE's own implementation and my guess too is that is has to do with hasLayout. What the relation of hasLayout is to any kind of standards-based layoutmodel is beyond my comprehension; I think it is just an internal hack to speed up rendering but is also the reason why IE7 will not be fully standards compliant. And as long as they hold on to this kind of hacks that have no actual relation to the layoutmodel as prescribed by CSS2.1 IE will never be fully standards compliant and weird bugs/behaviors will always be present.

    Posted by Tino Zijdel at

  4. We don’t want both, which one do you like?

    11. Act as if hasLayout doesn't exist.

    Posted by zcorpan at

  5. set zoom to 1 or writing-mode to tb-rl.

    Posted by Lon at

  6. I've just completed a script that required me to wade into this quagmire, and you're exactly right: it's all down to hasLayout.

    When an element hasLayout, the border width is excluded from offsetLeft et al; you need to add in the clientLeft of the element in question to get the 'true' offsetLeft (i.e., the same value that would be returned if hasLayout is false). Getting the border width itself is unreliable, as IE will return the border in the units with which it was set and so require correction if the border was set in points, ems, percentage, etc.

    This behaviour has an analogue in other browsers, such as Firefox: if an element has position: absolute in Firefox, it also will require one to add on the border width to get the same value as if the element were positioned relatively or statically.

    Additionally, neither Firefox nor IE (nor Safari, IIRC) will let you know about any border set on the BODY or HTML elements, so you'll have to get that width as well to get the true location of an element relative to the top-left corner of the page.

    The test page I used to suss all this out is here.

    I also have functions to 'getLeft' and 'getTop' based on my research if you're interested, though I'm pretty certain that they do not yet account for all possible combinations of borders, margins, padding, positioning, display and hasLayout in all browsers. If you want them, let me know.

    Posted by setmajer at

  7. How id be interested in that script file if you've still got it. I've been adding to my own getLeft, getTop functions for years and still dont have it perfect for all layouts. The most irretation bug is if you have an element with

    position:relative; float:left;

    This element will sit happily within a table cell or another layout, its offsetLeft and clientLeft will return you 0, which is fine, but if offsetParent is not the table cell, which is a problem.

    Anyway, we could swap scripts if you like, perhaps we'll cover more angles this way.

    Posted by Chris Knight at