119

Can someone show me how to get the top & left position of a div or span element when one is not specified?

ie:

<span id='11a' style='top:55px;' onmouseover="GetPos(this);">stuff</span>
<span id='12a' onmouseover="GetPos(this);">stuff</span>

In the above, if I do:

document.getElementById('11a').style.top

The value of 55px is returned. However, if I try that for span '12a', then nothing gets returned.

I have a bunch of div/spans on a page that I cannot specify the top/left properties for, but I need to display a div directly under that element.

HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
schmoopy
  • 6,419
  • 11
  • 54
  • 89

6 Answers6

218

You can call the method getBoundingClientRect() on a reference to the element. Then you can examine the top, left, right and/or bottom properties...

var offsets = document.getElementById('11a').getBoundingClientRect();
var top = offsets.top;
var left = offsets.left;

If using jQuery, you can use the more succinct code...

var offsets = $('#11a').offset();
var top = offsets.top;
var left = offsets.left;
alex
  • 479,566
  • 201
  • 878
  • 984
  • 11
    +1 for this answer, `getBoundingClientRect()` should be used - and this should be the accepted answer! But you don't need a _"modern browser"_ for this to work, see the compatibility list I showed here: http://stackoverflow.com/questions/1480133/how-can-i-get-an-objects-absolute-position-on-the-page-in-javascript/16626843#16626843. It works fine in IE 4.0+ (!), Chrome 1.0+, FF 3.0+, Safari 4.0+ and Opera. – Sk8erPeter May 18 '13 at 17:16
  • 26
    Note that `getBoundingClientRect()` returns values relative to the viewport, not the document. For that, you'd want something like `top = el.getBoundingClientRect().top + window.pageYOffset - el.ownerDocument.documentElement.clientTop`. – Zack Bloom Jan 17 '14 at 05:11
  • 1
    Also note that `getBoundingClientRect` takes `transform` into account. – ExpExc Feb 29 '16 at 06:56
  • This isn't accurate if the first non-absolutely-positioned child has margin-top or margin-left. There is currently no accurate solution on this page so if anyone knows, please post an answer. – Curtis Apr 17 '18 at 21:44
104

This function will tell you the x,y position of the element relative to the page. Basically you have to loop up through all the element's parents and add their offsets together.

function getPos(el) {
    // yay readability
    for (var lx=0, ly=0;
         el != null;
         lx += el.offsetLeft, ly += el.offsetTop, el = el.offsetParent);
    return {x: lx,y: ly};
}

However, if you just wanted the x,y position of the element relative to its container, then all you need is:

var x = el.offsetLeft, y = el.offsetTop;

To put an element directly below this one, you'll also need to know its height. This is stored in the offsetHeight/offsetWidth property.

var yPositionOfNewElement = el.offsetTop + el.offsetHeight + someMargin;
nickf
  • 537,072
  • 198
  • 649
  • 721
  • 5
    Unfortunately this method fails in Chrome when the element is inside a table with border. It will also fail in IE6 standards mode due to BODY margins. – GetFree Jul 17 '12 at 21:17
  • 1
    Just a warning for users of this code. This is relative to the page and not the window. It returns the same value if the user scrolls around using the scrollbars. Be careful. – Isaac Bolinger Feb 25 '14 at 20:07
  • thanks @IsaacBolinger just noticed it. Can someone tell me how i get it to change the values when the window is resized or the user scrolls? – David Fariña Jan 14 '16 at 14:32
  • @DavidFariña I used the geometry module "dom-geometry" of dojo for that. I don't know how to do it natively. – Isaac Bolinger Jan 17 '16 at 17:40
  • Downvoted - It may be obvious to more experienced users, but you haven't specified what exactly needs to be passed in for el (i.e. please provide a sample usage). – Matt Dec 19 '17 at 20:47
20

While @nickf's answer works. If you don't care for older browsers, you can use this pure Javascript version. Works in IE9+, and others

var rect = el.getBoundingClientRect();

var position = {
  top: rect.top + window.pageYOffset,
  left: rect.left + window.pageXOffset
};
Benjamin Intal
  • 2,748
  • 1
  • 25
  • 26
12

As Alex noted you can use jQuery offset() to get the position relative to the document flow. Use position() for its x,y coordinates relative to the parent.

EDIT: Switched document.ready for window.load because load waits for all of the elements so you get their size instead of simply preparing the DOM. In my experience, load results in fewer incorrectly Javascript positioned elements.

$(window).load(function(){ 
  // Log the position with jQuery
  var position = $('#myDivInQuestion').position();
  console.log('X: ' + position.left + ", Y: " + position.top );
});
Dylan Valade
  • 5,565
  • 6
  • 42
  • 56
9

For anyone needing just top or left position, slight modifications to @Nickf's readable code does the trick.

function getTopPos(el) {
    for (var topPos = 0;
        el != null;
        topPos += el.offsetTop, el = el.offsetParent);
    return topPos;
}

and

function getLeftPos(el) {
    for (var leftPos = 0;
        el != null;
        leftPos += el.offsetLeft, el = el.offsetParent);
    return leftPos;
}
Jens Frandsen
  • 832
  • 9
  • 13
2

I realize this is an old thread, but @alex 's answer needs to be marked as the correct answer

element.getBoundingClientRect() is an exact match to jQuery's $(element).offset()

And it's compatible with IE4+ ... https://developer.mozilla.org/en-US/docs/Web/API/Element.getBoundingClientRect

lukeed
  • 409
  • 2
  • 5
  • 13