Get real offset left/top of element with inline offsetparent

10,292

Solution 1

I ended up going with WebKit's window.webkitConvertPointFromNodeToPage, but I kept hitting a bug where it would return a position that was totally wrong. Further investigation revealed that if the node in question was display: inline, then it would return the position of the last block element in the hierarchy.

Searching for a resolution for this image turned up nothing (all I found was very basic information on what webkitConvertPointFromNodeToPage actually did and WebKit's sourcecode).

By guessing I found out that it returned the correct position if the element had display: inline-block, so if the element was inline then I changed it to inline-block and then calculated the position.

If anyone has a better solution for this problem I would love to hear from you!

Edit:

Turns out changing display style to inline-block is not always a good idea, so instead of doing that I'm using this method:

var offset = {x: 0, y: 0};
if ( getStyle(el, 'display') == 'inline' ) {
    offset.x = el.offsetLeft - el.parentNode.offsetLeft;
    offset.y = el.offsetTop - el.parentNode.offsetTop;
}

var point = window.webkitConvertPointFromNodeToPage(el, new WebKitPoint(0, 0));

return {
    x: Math.round(point.x + offset.x),
    y: Math.round(point.y + offset.y)
}

I'm taking the inline child's offsetTop/Left and subtracting that from it's parent. I'm not really sure how it works on parents that have display: inline, but it works 90% of the time.

But if anyone has a better idea I'm still open for suggestions.

Solution 2

Probably here you will find the description of the ideas used in the source code of jQuery.offset.

If you look here you can see that offsetLeft and offsetTop works not quite correct in the old IE versions.

I understand that it's interesting to understand how this or other things can be implemented. How you see the source code of jQuery.offset function is not so easy. If you want that your code works correct and be browser independent you should better just use jQuery.offset instead of writing his own implementation it.

Solution 3

Examination of the webkitConvertPointFromNodeToPage source code reveals that it calculates using the element renderer object, and if no such renderer exists, it uses the neareset ancestor that has a renderer. However, when an ancestor renderer is used, it doesn't adjust the offset to account for the origin diffence between the target and it's ancestor's origin. This means the function works correctly when the point is given relative to the containing renderer. If the element you're calculating coordinates for doesn't have a renderer, you need to manually adjust the offset to the nearest ancestor that does have it (using offsetLeft/Top). To know exactly which elements have renderers would require more research, but generally any element that has no content but affects the display of other nodes, such as SPAN, does not need a renderer.

Solution 4

I had the same problem When using $.offset().left with jQuery, trying to get the position of a word within a paragraph.

Using $.offset().left inside of a $(document).ready() function yielded an incorrect result.

Using $.offset().left in a $(window).load() function solved my problem in WebKit.

This is particularly relevant where there might be floated image elements or fonts that will affect the layout.

Share:
10,292
Erik Rothoff
Author by

Erik Rothoff

I love code.

Updated on June 17, 2022

Comments

  • Erik Rothoff
    Erik Rothoff almost 2 years

    I'm trying to get the coordinates of an element on a page. I've been using the standard way to obtain it:

    var el = element, pos = {x: 0, y: 0};
    while ( el ) {
        pos.x += el.offsetLeft;
        pos.y += el.offsetTop;
        el = el.offsetParent;
    }
    

    But this method fails when the element in question has display: block, and one of the offsetParents has display: inline;. This is due to the fact described in this thread:

    The element starts in the middle of the text

    After some trying with jQuery it turns out that their .offset()-method returns the correct offset, and I've looked through the source but not found exactly how they do it. So my question is: how do I get the exact position? I can't use jQuery for this project, and the method in the thread described earlier is to cumbersome, adding an element and testing is too much work (performance perspective), and using Element.getBoundingClientRect is not available either.

    If you feel like trying it out you can go to Apple.com open your debugger of choice and type in the following:

    var el, el2;
    el = el2 = document.querySelector('#worldwide span');
    var pos = {x: 0, y: 0};
    while ( el2 ) {
        pos.x += el2.offsetLeft;
        pos.y += el2.offsetTop;
        el2 = el2.offsetParent;
    }
    alert("Calculated position: " + pos.x + "x" + pos.y + " window size: " + screen.width + "x" + screen.height);
    

    With this code I get: Calculated position: 1354x988 window size: 1280x800 (ie. the offset left is way of the screen, which it clearly isn't)

    How is this possible? Any work-around ideas? Approximations? It does not have to be exact, but it has to be better than before. Thanks.

    Edit: This is for the WebKit rendering engine, to clarify.