Forum Moderators: open

Message Too Old, No Replies

How can I get the relative position of an HTML element using DOM?

         

bpejman

12:41 am on Jan 27, 2010 (gmt 0)

10+ Year Member



Hi Everyone,

Is there any way I can find the x and y coordinates of an HTML element that's positioned relatively on a page?

Unfortunately, both offsetLeft and offsetTop do not account for border widths. I solved that problem by building my div elements using DOM and specifying the width of each border by doing el.style.borderWidth = 'Xpx'; where X is a number of your choice (hope this helps someone out there).

In my function that captures the X and Y coords, I'm using el.parentNode.style.borderLeftWidth for the x coordinate and el.parentNode.style.borderTopWidth for the y coordinate and I'm adding those values to el.parentNode.offsetLeft for x and el.parentNode.offsetTop for y coordinate.

Everything works fine when all my HTML elements on the page have a position of absolute. However, as soon as a parent element's position turns relative, the coordinates returned are no longer accurate.

I've been reading that FireFox has a built-in API as of version 3.5 called el.getBoundingClientRect().

This is a major problem on the web for many users so if I find anything, I'll post it here but if anyone knows of any ways, I would gladly appreciate a hint or direction.

Thanks!
Bobby

astupidname

10:37 pm on Jan 27, 2010 (gmt 0)

10+ Year Member



When attempting to determine an element's position relative to the page, don't go by parentNode's, go by offsetParent's. This getElementPosition function has been working out well for me:
function getElementPosition(el) {
var l = 0, t = 0;
while (el.offsetParent) {
l += el.offsetLeft;
t += el.offsetTop;
el = el.offsetParent;
}
return {left:l, top:t};
}

//example (pass an element reference):
var pos = getElementPosition(element);
var s = 'element\'s left coordinate on the page is: '+ pos.left;
s += '\nelement\'s top coordinate on the page is: '+ pos.top;
alert(s);

vol7ron

1:49 pm on Jan 28, 2010 (gmt 0)

10+ Year Member



Can we paint a picture so I have a better understanding of what you're doing?

That is, let's say you have a DIV centered on the page, border 10px all around. Inside that, you have another DIV text-aligned right, border 5px:

<div style="border:10px solid black;text-align:right;"> 
<div>foo</div>
</div>

Where does the error occur? When you hover your mouse over the border, or is it reporting the wrong offset from the parent?

bpejman

5:15 am on Jan 29, 2010 (gmt 0)

10+ Year Member



Thank you for the code! I will give it a try and see if it solves my problem! :)

Vol7ron: I should have provided code for this. My problem is that I'm seeing the wrong results rather than getting an error.

So, I have a code that you can run and see what I'm trying to achieve. Let's stick to Firefox for now as our browser. Please note that the div element I have has 'position:absolute' applied with no padding and margin size of 10px. This also includes the body and html elements both having a position of absolute value but no margin and padding.

One last thing to note is that I have a "p" element specified after the "div" element. If you run this code in your browser, you'll notice a "10, 10" will be returned and both the left offset and top offset is of equal distance from the edge of the browser window. So far so good and I would expect that as my result.


<html>
<head>
<style type="text/css">
html,body{
position:absolute;
height:100%;width:100%;
padding:0px; margin:0px;
}
div {
position:absolute;
height:100px; width:100px;
padding:0px; margin:10px;
border: 1px dotted #000000;
}
</style>
</head>
<body>
<div id="d0"></div>
<p id="result"></p>
<script type="text/javascript">
function getXY(el) {
var x = 0;
var y = 0;
x += el.offsetLeft;
y += el.offsetTop;
while ( el.parentNode )
{
x += el.parentNode.offsetLeft;
y += el.parentNode.offsetTop;
if ( isNaN(el.parentNode.style.borderLeftWidth) )
x += parseInt(el.parentNode.style.borderLeftWidth);
if ( isNaN(el.parentNode.style.borderTopWidth) )
y += parseInt(el.parentNode.style.borderTopWidth);
el = el.parentNode;
if ( typeof el.parentNode.tagName == 'undefined' ) break;
}
return [x, y];
}
var res = getXY(document.getElementById("d0"));
document.getElementById("result").innerHTML = res[0] + ", " + res[1];
</script>
</body>
</html>

Now, if I place the "p" element before the "div" element in the body, simply switching the order, the X and Y coordinates returned for my div will still be "10, 10" but offset top is waaayyy larger than offset left so it just can't be "10, 10" but more like "10, 30" or something to that effect.

This is all because the "p" element has no absolute position defined so by default it's inherited or relative.

What I would like to see is a "10,30" or "10,20" or similar where the Y is larger than X.

I hope this makes sense in what I'm trying to achieve.

Thanks so much for looking into this and I will try the code that 'astupidname' provided me to see if it helps.

bpejman

7:03 pm on Jan 29, 2010 (gmt 0)

10+ Year Member



Vol7ron,

I tried your code but received the same values as the function I posted earlier.

I'm really not sure how to solve this problem because what the eye sees on the screen is not 10, 10. It's more like 10, 30 or 10,40 coordinates but for some reason offsetLeft or offsetParent keep returning 10,10.

I thought about adding "*{position:inherit;}" to my css which solves my problem but messes with the stylesheet.

Still looking around for a solution...

astupidname

8:45 pm on Jan 29, 2010 (gmt 0)

10+ Year Member



The "result" paragraph does not have any initial content or height, so when you take your measurement and then add text in to "result" you have now changed the real values after having taken your measurement.

bpejman

12:20 am on Jan 30, 2010 (gmt 0)

10+ Year Member



Very nice! You solved my problem. :) I put in a "&nbsp;" and it all works. You made my weekend bud. Thank you.

Bobby

vol7ron

3:34 pm on Mar 11, 2010 (gmt 0)

10+ Year Member



I just wanted to add that astupidname provided you the code. Unfortunately, I wasn't available to help out with this.

vol7ron

bpejman

4:02 pm on Mar 11, 2010 (gmt 0)

10+ Year Member



Thanks for the clarification. My mistake. astupidname, the only thing I can recommend if it helps is to account for border widths in your function when traversing the DOM.

If I'm traversing up and left, I would check for:


if (isNaN(_el.parentNode.style.borderLeftWidth))
x+=parseInt(_el.parentNode.style.borderLeftWidth);
if (isNaN(_el.parentNode.style.borderTopWidth))
y+=parseInt(_el.parentNode.style.borderTopWidth);