David Cramer's Blog

Get X/Y Offsets for an Object in JavaScript

I had to fix a strange bug today in the iBegin Share widget. On one of our pages (the readme specifically) it was positioning wrong. The goal was to position it 5px below the bottom of the object it’s attached to. Easily enough I was able to Google and find the same 10 results that said “here is what you do to get the *correct* absolute positions for an object”. None of them actually worked :)

So, too many hours later, and after not having a single person being able to clue me in on the problem, I found the issue. We had a container which had position: relative; and border-width: 25px 0;. To my suprise, the 25px border was what wasnt being counted. This didn’t seem to happen in Internet Explorer, only Firefox (and I believe Opera as well). I now give you a fully* (I guarantee nothing) working version of the getXY function.

Update: After doing a little bit more research this may be related to the hasLayout style property.

(You can also grab this over at PasteThat)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
* Returns the absolute X and Y positions of an object.
* @param {HTMLObject} obj HTML Object.
* @return {Object} Returns an accessor with .x and .y values.
*/
function getXY(obj)
{
    var curleft = 0;
    var curtop = obj.offsetHeight + 5;
    var border;
    if (obj.offsetParent)
    {
        do
        {
            // XXX: If the element is position: relative we have to add borderWidth
            if (getStyle(obj, 'position') == 'relative')
            {
                if (border = _pub.getStyle(obj, 'border-top-width')) curtop += parseInt(border);
                if (border = _pub.getStyle(obj, 'border-left-width')) curleft += parseInt(border);
            }
            curleft += obj.offsetLeft;
            curtop += obj.offsetTop;
        }
        while (obj = obj.offsetParent)
    }
    else if (obj.x)
    {
        curleft += obj.x;
        curtop += obj.y;
    }
    return {'x': curleft, 'y': curtop};
}
/**
* Returns the specified computed style on an object.
* @param {HTMLObject} obj HTML Object
* @param {String} styleProp Property name.
* @return {Mixed} Computed style on object.
*/
function getStyle(obj, styleProp)
{
    if (obj.currentStyle)
    return obj.currentStyle[styleProp];
    else if (window.getComputedStyle)
    return document.defaultView.getComputedStyle(obj,null).getPropertyValue(styleProp);
}