[position] Get position/offset of element relative to a parent container?

I'm used to working with jQuery. In my current project however I use zepto.js. Zepto doesn't provide a position() method like jQuery does. Zepto only comes with offset().

Any idea how I can retrieve the offset of a container relative to a parent with pure js or with Zepto?

This question is related to position offset zepto

The answer is


Add the offset of the event to the parent element offset to get the absolute offset position of the event.

An example :

HTMLElement.addEventListener('mousedown',function(e){

    var offsetX = e.offsetX;
    var offsetY = e.offsetY;

    if( e.target != this ){ // 'this' is our HTMLElement

        offsetX = e.target.offsetLeft + e.offsetX;
        offsetY = e.target.offsetTop + e.offsetY;

    }
}

When the event target is not the element which the event was registered to, it adds the offset of the parent to the current event offset in order to calculate the "Absolute" offset value.

According to Mozilla Web API: "The HTMLElement.offsetLeft read-only property returns the number of pixels that the upper left corner of the current element is offset to the left within the HTMLElement.offsetParent node."

This mostly happens when you registered an event on a parent which is containing several more children, for example: a button with an inner icon or text span, an li element with inner spans. etc...


in pure js just use offsetLeft and offsetTop properties.
Example fiddle: http://jsfiddle.net/WKZ8P/

_x000D_
_x000D_
var elm = document.querySelector('span');_x000D_
console.log(elm.offsetLeft, elm.offsetTop);
_x000D_
p   { position:relative; left:10px; top:85px; border:1px solid blue; }_x000D_
span{ position:relative; left:30px; top:35px; border:1px solid red; }
_x000D_
<p>_x000D_
    <span>paragraph</span>_x000D_
</p>
_x000D_
_x000D_
_x000D_


Example

So, if we had a child element with an id of "child-element" and we wanted to get it's left/top position relative to a parent element, say a div that had a class of "item-parent", we'd use this code.

var position = $("#child-element").offsetRelative("div.item-parent");
alert('left: '+position.left+', top: '+position.top);

Plugin Finally, for the actual plugin (with a few notes expalaining what's going on):

// offsetRelative (or, if you prefer, positionRelative)
(function($){
    $.fn.offsetRelative = function(top){
        var $this = $(this);
        var $parent = $this.offsetParent();
        var offset = $this.position();
        if(!top) return offset; // Didn't pass a 'top' element 
        else if($parent.get(0).tagName == "BODY") return offset; // Reached top of document
        else if($(top,$parent).length) return offset; // Parent element contains the 'top' element we want the offset to be relative to 
        else if($parent[0] == $(top)[0]) return offset; // Reached the 'top' element we want the offset to be relative to 
        else { // Get parent's relative offset
            var parent_offset = $parent.offsetRelative(top);
            offset.top += parent_offset.top;
            offset.left += parent_offset.left;
            return offset;
        }
    };
    $.fn.positionRelative = function(top){
        return $(this).offsetRelative(top);
    };
}(jQuery));

Note : You can Use this on mouseClick or mouseover Event

$(this).offsetRelative("div.item-parent");

I got another Solution. Subtract parent property value from child property value

$('child-div').offset().top - $('parent-div').offset().top;

I did it like this in Internet Explorer.

function getWindowRelativeOffset(parentWindow, elem) {
    var offset = {
        left : 0,
        top : 0
    };
    // relative to the target field's document
    offset.left = elem.getBoundingClientRect().left;
    offset.top = elem.getBoundingClientRect().top;
    // now we will calculate according to the current document, this current
    // document might be same as the document of target field or it may be
    // parent of the document of the target field
    var childWindow = elem.document.frames.window;
    while (childWindow != parentWindow) {
        offset.left = offset.left + childWindow.frameElement.getBoundingClientRect().left;
        offset.top = offset.top + childWindow.frameElement.getBoundingClientRect().top;
        childWindow = childWindow.parent;
    }

    return offset;
};

=================== you can call it like this

getWindowRelativeOffset(top, inputElement);

I focus on IE only as per my focus but similar things can be done for other browsers.


Sure is easy with pure JS, just do this, work for fixed and animated HTML 5 panels too, i made and try this code and it works for any brower (include IE 8):

<script type="text/javascript">
    function fGetCSSProperty(s, e) {
        try { return s.currentStyle ? s.currentStyle[e] : window.getComputedStyle(s)[e]; }
        catch (x) { return null; } 
    }
    function fGetOffSetParent(s) {
        var a = s.offsetParent || document.body;

        while (a && a.tagName && a != document.body && fGetCSSProperty(a, 'position') == 'static')
            a = a.offsetParent;
        return a;
    }
    function GetPosition(s) {
        var b = fGetOffSetParent(s);

        return { Left: (b.offsetLeft + s.offsetLeft), Top: (b.offsetTop + s.offsetTop) };
    }    
</script>