110

I want to get an object's absolute x,y position on the page in Javascript. How can I do this?

I tried obj.offsetTop and obj.offsetLeft, but those only give the position relative to the parent element. I guess I could loop through and add the parent's offset, and its parent's offset, and so on until I get to the object with no parent, but it seems like there should be a better way. Googling didn't turn up much, and even SO site search isn't finding anything.

Also, I can't use jQuery.

bfavaretto
  • 71,580
  • 16
  • 111
  • 150
Kip
  • 107,154
  • 87
  • 232
  • 265

2 Answers2

196
var cumulativeOffset = function(element) {
    var top = 0, left = 0;
    do {
        top += element.offsetTop  || 0;
        left += element.offsetLeft || 0;
        element = element.offsetParent;
    } while(element);

    return {
        top: top,
        left: left
    };
};

(Method shamelessly stolen from PrototypeJS; code style, variable names and return value changed to protect the innocent)

eyelidlessness
  • 62,413
  • 11
  • 90
  • 94
161

I would definitely suggest using element.getBoundingClientRect().

https://developer.mozilla.org/en-US/docs/Web/API/element.getBoundingClientRect

Summary

Returns a text rectangle object that encloses a group of text rectangles.

Syntax

var rectObject = object.getBoundingClientRect();

Returns

The returned value is a TextRectangle object which is the union of the rectangles returned by getClientRects() for the element, i.e., the CSS border-boxes associated with the element.

The returned value is a TextRectangle object, which contains read-only left, top, right and bottom properties describing the border-box, in pixels, with the top-left relative to the top-left of the viewport.

Here's a browser compatibility table taken from the linked MDN site:

+---------------+--------+-----------------+-------------------+-------+--------+
|    Feature    | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari |
+---------------+--------+-----------------+-------------------+-------+--------+
| Basic support | 1.0    | 3.0 (1.9)       | 4.0               | (Yes) | 4.0    |
+---------------+--------+-----------------+-------------------+-------+--------+

It's widely supported, and is really easy to use, not to mention that it's really fast. Here's a related article from John Resig: http://ejohn.org/blog/getboundingclientrect-is-awesome/

You can use it like this:

var logo = document.getElementById('hlogo');
var logoTextRectangle = logo.getBoundingClientRect();

console.log("logo's left pos.:", logoTextRectangle.left);
console.log("logo's right pos.:", logoTextRectangle.right);

Here's a really simple example: http://jsbin.com/awisom/2 (you can view and edit the code by clicking "Edit in JS Bin" in the upper right corner).

Or here's another one using Chrome's console: Using element.getBoundingClientRect() in Chrome

Note:

I have to mention that the width and height attributes of the getBoundingClientRect() method's return value are undefined in Internet Explorer 8. It works in Chrome 26.x, Firefox 20.x and Opera 12.x though. Workaround in IE8: for width, you could subtract the return value's right and left attributes, and for height, you could subtract bottom and top attributes (like this).

Sk8erPeter
  • 6,899
  • 9
  • 48
  • 67
  • 1
    offsetLeft returns different values in ie and firefox, ie didn't include the margins and ff also gave incorrect result but this solved it great got what i needed, thanks, works perfect – Diljeet Aug 31 '13 at 23:01
  • 73
    Is this a completely different use case? scroll the page down and check your values again... `getBoundingClientRect()` is for the position relative to the scrolled window... your top value will change to negative as you scroll past the logo. – jondavidjohn Sep 21 '13 at 02:16
  • 19
    @jondavidjohn Sure, but that can be easily adjusted by adding `window.pageYOffset` (or, if you really need IE8 compatibility, [`(window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop`](https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY#Notes)). Same for horizontal scrolling. – user123444555621 Aug 25 '14 at 06:31
  • 24
    I think you should edit the answer to include this page offset snippet in a way that will answer the original OP question. Getting to be the most upvoted answer brings some responsibility with it ;) – etov Oct 02 '14 at 17:54
  • @user123444555621 Should I add the `window.pageYOffset` to `bottom`, too? And `window.pageXOffset` to `right`, too? In order to have consistent `top`, `right`, `bottom`, `left` values? – tonix Oct 21 '15 at 14:19
  • This method is, in my opinion, meant to solve exactly this issue. So +1 from me, I hope the OP changes the accepted answer because, although the other one is good, this one is better. – tfrascaroli Apr 21 '17 at 06:57
  • 5
    In my case, `getBoundingClientRect` returned wrong offset from top. Suggestion of @eyelidlessness is working. – AntonAL May 08 '19 at 13:30
  • 10
    But `getBoundingClientRect` doesn't return `absolute` positions of element's `x`, `y` – Mike Czarnota Oct 04 '19 at 08:21
  • 4
    @user123444555621 This statement is not correct, while it may work for most use cases, `window.pageYOffset` will not work if your element is in a scrollable element that is not the body of the page – Tofandel May 19 '21 at 17:53
  • 1
    The question asked for "relative to page", not "relative to viewport". – Rick James Dec 11 '22 at 05:24