Retrieve the position (X,Y) of an HTML element

    |
  • Added:
  • |
  • In: Wordpress

I want to know how to get the X and Y position of HTML elements such as img and div in JavaScript.

This Question Has 21 Answeres | Orginal Question | monaung

After much research and testing this seems to work

function getPosition(e) { var isNotFirefox = (navigator.userAgent.toLowerCase().indexOf('firefox') == -1); var x = 0, y = 0; while (e) { x += e.offsetLeft - e.scrollLeft + (isNotFirefox ? e.clientLeft : 0); y += e.offsetTop - e.scrollTop + (isNotFirefox ? e.clientTop : 0); e = e.offsetParent; } return { x: x + window.scrollX, y: y + window.scrollY }; } 

see http://jsbin.com/xuvovalifo/edit?html,js,output

You might be better served by using a JavaScript framework, that has functions to return such information (and so much more!) in a browser-independant fashion. Here are a few:

With these frameworks, you could do something like: $('id-of-img').top to get the y-pixel coordinate of the image.

You can add two properties to Element.prototype to get the top/left of any element.

Object.defineProperty( Element.prototype, 'documentOffsetTop', { get: function () { return this.offsetTop + ( this.offsetParent ? this.offsetParent.documentOffsetTop : 0 ); } } ); Object.defineProperty( Element.prototype, 'documentOffsetLeft', { get: function () { return this.offsetLeft + ( this.offsetParent ? this.offsetParent.documentOffsetLeft : 0 ); } } ); 

This is called like this:

var x = document.getElementById( 'myDiv' ).documentOffsetLeft; 

Here's a demo comparing the results to jQuery's offset().top and .left: http://jsfiddle.net/ThinkingStiff/3G7EZ/

If you are using jQuery, this could be a simple solution:

<script> var el = $("#element"); var position = el.position(); console.log( "left: " + position.left + ", top: " + position.top ); </script> 

This worked for me (modified from highest voted answer):

function getOffset(el) { el = el.getBoundingClientRect(); return { left: el.left + window.scrollX, top: el.top + window.scrollY } } 

Using this we can call

getOffset(element).left 

or

getOffset(element).top 

if using jQuery, the dimensions plugin is excellent and allows you specify exactly what you want.

e.g.

Relative position, absolute position, absolute position without padding, with padding...

It goes on, let's just say there is a lot you can do with it.

Plus the bonus of using jQuery is it's lightweight file size and easy use, you won't go back to JavaScript without it afterwards.

The cleanest approach I have found is a simplified version of the technique used by jQuery's offset. Similar to some of the other answers it starts with getBoundingClientRect; it then uses the window and the documentElement to adjust for scroll position as well as things like the margin on the body (often the default).

var rect = el.getBoundingClientRect(); var docEl = document.documentElement; var rectTop = rect.top + window.pageYOffset - docEl.clientTop; var rectLeft = rect.left + window.pageXOffset - docEl.clientLeft; 

var els = document.getElementsByTagName("div"); var docEl = document.documentElement; for (var i = 0; i < els.length; i++) { var rect = els[i].getBoundingClientRect(); var rectTop = rect.top + window.pageYOffset - docEl.clientTop; var rectLeft = rect.left + window.pageXOffset - docEl.clientLeft; els[i].innerHTML = "<b>" + rectLeft + ", " + rectTop + "</b>"; }
div { width: 100px; height: 100px; background-color: red; border: 1px solid black; } #rel { position: relative; left: 10px; top: 10px; } #abs { position: absolute; top: 250px; left: 250px; }
<div id="rel"></div> <div id="abs"></div> <div></div>

Since different browsers are rendering border, padding, margin and etc in different way. I wrote a little function to retrieve top and left positions of specific element in every root element that you want in precise dimension:

function getTop(root, offset) { var rootRect = root.getBoundingClientRect(); var offsetRect = offset.getBoundingClientRect(); return offsetRect.top - rootRect.top; } 

For retrieve left position you must return:

 return offsetRect.left - rootRect.left; 

To retrieve the position relative to the page efficiently, and without using a recursive function: (includes IE also)

var element = document.getElementById('elementId'); //replace elementId with your element's Id. var rect = element.getBoundingClientRect(); var elementLeft,elementTop; //x and y var scrollTop = document.documentElement.scrollTop? document.documentElement.scrollTop:document.body.scrollTop; var scrollLeft = document.documentElement.scrollLeft? document.documentElement.scrollLeft:document.body.scrollLeft; elementTop = rect.top+scrollTop; elementLeft = rect.left+scrollLeft; 

If page includes - at least- any "DIV", the function given by meouw throws the "Y" value beyond current page limits. In order to find the exact position, you need to handle both "offsetParent"s and "parentNode"s.

Try the code given below (it is checked for FF2):

 var getAbsPosition = function(el){ var el2 = el; var curtop = 0; var curleft = 0; if (document.getElementById || document.all) { do { curleft += el.offsetLeft-el.scrollLeft; curtop += el.offsetTop-el.scrollTop; el = el.offsetParent; el2 = el2.parentNode; while (el2 != el) { curleft -= el2.scrollLeft; curtop -= el2.scrollTop; el2 = el2.parentNode; } } while (el.offsetParent); } else if (document.layers) { curtop += el.y; curleft += el.x; } return [curtop, curleft]; }; 

I did it like this so it was cross-compatible with old browsers.

// For really old browser's or incompatible ones function getOffsetSum(elem) { var top = 0, left = 0, bottom = 0, right = 0 var width = elem.offsetWidth; var height = elem.offsetHeight; while (elem) { top += elem.offsetTop; left += elem.offsetLeft; elem = elem.offsetParent; } right = left + width; bottom = top + height; return { top: top, left: left, bottom: bottom, right: right, } } function getOffsetRect(elem) { var box = elem.getBoundingClientRect(); var body = document.body; var docElem = document.documentElement; var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop; var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft; var clientTop = docElem.clientTop; var clientLeft = docElem.clientLeft; var top = box.top + scrollTop - clientTop; var left = box.left + scrollLeft - clientLeft; var bottom = top + (box.bottom - box.top); var right = left + (box.right - box.left); return { top: Math.round(top), left: Math.round(left), bottom: Math.round(bottom), right: Math.round(right), } } function getOffset(elem) { if (elem) { if (elem.getBoundingClientRect) { return getOffsetRect(elem); } else { // old browser return getOffsetSum(elem); } } else return null; } 

More about coordinates in JavaScript here: http://javascript.info/tutorial/coordinates

The libraries go to some lengths to get accurate offsets for an element.
here's a simple function that does the job in every circumstances that I've tried.

function getOffset( el ) { var _x = 0; var _y = 0; while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) { _x += el.offsetLeft - el.scrollLeft; _y += el.offsetTop - el.scrollTop; el = el.offsetParent; } return { top: _y, left: _x }; } var x = getOffset( document.getElementById('yourElId') ).left; 

How about something like this, by passing ID of the element and it will return the left or top, we can combine them:

1) find left

function findLeft(element) { var rec = document.getElementById(element).getBoundingClientRect(); return rec.left + window.scrollX; } //call it like findLeft('#header'); 

2) find top

function findTop(element) { var rec = document.getElementById(element).getBoundingClientRect(); return rec.top + window.scrollY; } //call it like findTop('#header'); 

or 3) find left and top together

function findTopLeft(element) { var rec = document.getElementById(element).getBoundingClientRect(); return {top: rec.top + window.scrollY, left: rec.left + window.scrollX}; } //call it like findTopLeft('#header'); 

The correct approach is to use element.getBoundingClientRect():

var rect = element.getBoundingClientRect(); console.log(rect.top, rect.right, rect.bottom, rect.left); 

Internet Explorer has supported this since as long as you are likely to care about and it was finally standardized in CSSOM Views.?All other browsers adopted it a long time ago.

Some browsers also return height and width properties, though this is non-standard. If you're worried about older browser compatibility, check this answer's revisions for an optimised degrading implementation.

The values returned by element.getBoundingClientRect() are relative to the viewport. If you need it relative to another element, simply subtract one rectangle from the other:

var bodyRect = document.body.getBoundingClientRect(), elemRect = element.getBoundingClientRect(), offset = elemRect.top - bodyRect.top; alert('Element is ' + offset + ' vertical pixels from <body>'); 

jQuery .offset() will get the current coordinates of the first element, or set the coordinates of every element, in the set of matched elements, relative to the document.

This is the best code I've managed to create (works in iframes as well, unlike jQuery's offset()). Seems webkit has a bit of a different behavior.

Based on meouw's comment:

function getOffset( el ) { var _x = 0; var _y = 0; while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) { _x += el.offsetLeft - el.scrollLeft; _y += el.offsetTop - el.scrollTop; // chrome/safari if ($.browser.webkit) { el = el.parentNode; } else { // firefox/IE el = el.offsetParent; } } return { top: _y, left: _x }; } 

HTML elements on most browsers will have:-

offsetLeft offsetTop 

These specifiy the position of the element relative its nearest parent that has layout. This parent can often be accessed bif the offsetParent property.

IE and FF3 have

clientLeft clientTop 

These properties are less common, they specify an elements position with its parents client area (padded area is part of the client area but border and margin is not).

I successfully used Andy E's solution to position a bootstrap 2 modal depending on what link in a table row a user clicks on. The page is a Tapestry 5 page and javascript below is imported in the java page class.

javascript:

function setLinkPosition(clientId){ var bodyRect = document.body.getBoundingClientRect(), elemRect = clientId.getBoundingClientRect(), offset = elemRect.top - bodyRect.top; offset = offset + 20; $('#serviceLineModal').css("top", offset); 

}

My modal code:

<div id="serviceLineModal" class="modal hide fade add-absolute-position" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="top:50%;"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button> <h3 id="myModalLabel">Modal header</h3> </div> <div class="modal-body"> <t:zone t:id="modalZone" id="modalZone"> <p>You selected service line number: ${serviceLineNumberSelected}</p> </t:zone> </div> <div class="modal-footer"> <button class="btn" data-dismiss="modal" aria-hidden="true">Close</button> <!-- <button class="btn btn-primary">Save changes</button> --> </div> 

The link in the loop:

<t:loop source="servicesToDisplay" value="service" encoder="encoder"> <tr style="border-right: 1px solid black;"> <td style="white-space:nowrap;" class="add-padding-left-and-right no-border"> <a t:type="eventLink" t:event="serviceLineNumberSelected" t:context="service.serviceLineNumber" t:zone="pageZone" t:clientId="modalLink${service.serviceLineNumber}" onmouseover="setLinkPosition(this);"> <i class="icon-chevron-down"></i> <!-- ${service.serviceLineNumber} --> </a> </td> 

And the java code in the page class:

void onServiceLineNumberSelected(String number){ checkForNullSession(); serviceLineNumberSelected = number; addOpenServiceLineDialogCommand(); ajaxResponseRenderer.addRender(modalZone); } protected void addOpenServiceLineDialogCommand() { ajaxResponseRenderer.addCallback(new JavaScriptCallback() { @Override public void run(JavaScriptSupport javascriptSupport) { javascriptSupport.addScript("$('#serviceLineModal').modal('show');"); } }); } 

Hope this helps someone, this post helped out.

Difference between small and little

function getPosition( el ) { var x = 0; var y = 0; while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) { x += el.offsetLeft - el.scrollLeft; y += el.offsetTop - el.scrollTop; el = el.offsetParent; } return { top: y, left: x }; } 

Look a example coordinates: http://javascript.info/tutorial/coordinates

Just thought I'd throw this out there as well.
I haven't been able to test it in older browsers, but it works in the latest of the top 3. :)

Element.prototype.getOffsetTop = function() { return ( this.parentElement )? this.offsetTop + this.parentElement.getOffsetTop(): this.offsetTop; }; Element.prototype.getOffsetLeft = function() { return ( this.parentElement )? this.offsetLeft + this.parentElement.getOffsetLeft(): this.offsetLeft; }; Element.prototype.getOffset = function() { return {'left':this.getOffsetLeft(),'top':this.getOffsetTop()}; }; 

I've taken @meouw's answer, added in the clientLeft that allows for the border, and then created three versions:

getAbsoluteOffsetFromBody - similar to @meouw's, this gets the absolute position relative to the body or html element of the document (depending on quirks mode)

getAbsoluteOffsetFromGivenElement - returns the absolute position relative to the given element (relativeEl). Note that the given element must contain the element el, or this will behave the same as getAbsoluteOffsetFromBody. This is useful if you have two elements contained within another (known) element (optionally several nodes up the node tree) and want to make them the same position.

getAbsoluteOffsetFromRelative - returns the absolute position relative to the first parent element with position: relative. This is similar to getAbsoluteOffsetFromGivenElement, for the same reason but will only go as far as the first matching element.

getAbsoluteOffsetFromBody = function( el ) { // finds the offset of el from the body or html element var _x = 0; var _y = 0; while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) { _x += el.offsetLeft - el.scrollLeft + el.clientLeft; _y += el.offsetTop - el.scrollTop + el.clientTop; el = el.offsetParent; } return { top: _y, left: _x }; } getAbsoluteOffsetFromGivenElement = function( el, relativeEl ) { // finds the offset of el from relativeEl var _x = 0; var _y = 0; while( el && el != relativeEl && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) { _x += el.offsetLeft - el.scrollLeft + el.clientLeft; _y += el.offsetTop - el.scrollTop + el.clientTop; el = el.offsetParent; } return { top: _y, left: _x }; } getAbsoluteOffsetFromRelative = function( el ) { // finds the offset of el from the first parent with position: relative var _x = 0; var _y = 0; while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) { _x += el.offsetLeft - el.scrollLeft + el.clientLeft; _y += el.offsetTop - el.scrollTop + el.clientTop; el = el.offsetParent; if (el != null) { if (getComputedStyle !== 'undefined') valString = getComputedStyle(el, null).getPropertyValue('position'); else valString = el.currentStyle['position']; if (valString === "relative") el = null; } } return { top: _y, left: _x }; } 

If you are still having problems, particularly relating to scrolling, you could try looking at http://www.greywyvern.com/?post=331 - I noticed at least one piece of questionable code in getStyle which should be fine assuming browsers behave, but haven't tested the rest at all.


Search
I am...

Sajjad Hossain

I have five years of experience in web development sector. I love to do amazing projects and share my knowledge with all.

NEED HOSTING?
Are you searching for Good Quality hosting?
You can Try It!
Connect Social With PHPAns
Top