27

How do I find out the absolute position of an element on the current visible screen (viewport) using jQuery?

I am having position:relative, so offset() will only give the offset within the parent.

I have hierarchical divs, so $("#me").parent().offset() + $("#me").offset() doesn't help either.

I need the position in the window, not the document, so when the document is scrolled, the value should change.

I know I could add up all the parent offsets, but I want a cleaner solution.

var top = $("#map").offset().top + 
    $("#map").parent().offset().top + 
    $("#map").parent().parent().offset().top +
    $("#map").parent().parent().parent().offset().top;

Any ideas?

Update: I need to get the exact gap in pixels between the top of my div and the top of the document, including padding/margins/offset?

My code:

HTML

<div id="map_frame" class="frame" hidden="hidden">
    <div id="map_wrapper">
        <div id="map"></div>
    </div>
</div>

CSS

#map_frame{
    border:1px solid #800008;
}

#map_wrapper {
    position:relative;
    left:2%;
    top:1%;
    width:95%;
    max-height:80%;
    display:block;
}

#map {
    position:relative;
    height:100%;
    width:100%;
    display:block;
    border:3px solid #fff;
}

jQuery to resize the map to fill the screen*

var t = $("#map").offset().top + 
    $("#map").parent().offset().top + 
    $("#map").parent().parent().offset().top + 
    $("#map").parent().parent().parent().offset().top;

$("#map").height($(window).height() - t - ($(window).height() * 8 / 100));

Thanks...

ATOzTOA
  • 34,814
  • 22
  • 96
  • 117
  • `offset()` returns the offset relative to the document, does'nt matter how you've positioned your elements. How would the position of an element relative to, well anything, change on scroll? Are you sure you're not just looking for `scrollTop()` ? – adeneo Dec 18 '12 at 09:38
  • 2
    offset() will return the offset from the parent element if the style is `position:relative`. – ATOzTOA Dec 18 '12 at 09:43
  • When you scroll, the distance between the element and the top of the screen changes, right? – ATOzTOA Dec 18 '12 at 09:44
  • That distance is the scrollTop, and has nothing to do with the elements position, as elements are positioned whitin the document, and the window is what you see in your browser. And no, when the element is positioned relative, offset still returns the offset relative to the document, try it out and see. See the answer below, it should pretty much cover it. – adeneo Dec 18 '12 at 09:47
  • Perhaps see this solution: http://stackoverflow.com/questions/1567327/using-jquery-to-get-elements-position-relative-to-viewport – DextrousDave Dec 18 '12 at 09:48

3 Answers3

59

See .offset() here in the jQuery doc. It gives the position relative to the document, not to the parent. You perhaps have .offset() and .position() confused. If you want the position in the window instead of the position in the document, you can subtract off the .scrollTop() and .scrollLeft() values to account for the scrolled position.

Here's an excerpt from the doc:

The .offset() method allows us to retrieve the current position of an element relative to the document. Contrast this with .position(), which retrieves the current position relative to the offset parent. When positioning a new element on top of an existing one for global manipulation (in particular, for implementing drag-and-drop), .offset() is the more useful.

To combine these:

var offset = $("selector").offset();
var posY = offset.top - $(window).scrollTop();
var posX = offset.left - $(window).scrollLeft(); 

You can try it here (scroll to see the numbers change): http://jsfiddle.net/jfriend00/hxRPQ/

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Why am I getting different values for these even though position:relative is set? console.log($("#map").parent().parent().parent().offset().top); console.log($("#map").parent().parent().offset().top); console.log($("#map").parent().offset().top); console.log($("#map").offset().top); – ATOzTOA Dec 18 '12 at 10:00
  • @ATOzTOA - I can't answer your question because you've not disclosed HTML/CSS that surrounds #map. Parents don't always have the same offset as children (margins, padding, position settings, other children, float, etc...). Why bother with `.offset()` of parent objects? You don't need it. `.offset()` gives you the document position of the targeted object already accounting for parent offsets. – jfriend00 Dec 18 '12 at 10:06
  • 2
    Ok, so how do you get the exact gap in pixels between the top of my #map div and the top of the document, including padding/margin/offset? – ATOzTOA Dec 18 '12 at 10:22
  • 1
    I am getting offset() as 0, even though I can see gap between the top of the div and the top of the document. – ATOzTOA Dec 18 '12 at 10:23
  • 1
    @ATOzTOA - As I've said before, we'd have to see your exact HTML and CSS to know what's going on in your particular case. .offset() works as specified. There's nothing wrong with it so there's something peculiar about your particular situation that you haven't disclosed. There could be a negative scroll or there could be a container around the document (e.g. an iframe). I really have no idea what's in your HTML/CSS. Sorry, but I've built a complete working demo based on what you've told us to show you how it works. Can't do more with what you've given us. – jfriend00 Dec 18 '12 at 10:27
5

For the absolute coordinates of any jquery element I wrote this function, it probably doesnt work for all css position types but maybe its a good start for someone ..

function AbsoluteCoordinates($element) {
    var sTop = $(window).scrollTop();
    var sLeft = $(window).scrollLeft();
    var w = $element.width();
    var h = $element.height();
    var offset = $element.offset(); 
    var $p = $element;
    while(typeof $p == 'object') {
        var pOffset = $p.parent().offset();
        if(typeof pOffset == 'undefined') break;
        offset.left = offset.left + (pOffset.left);
        offset.top = offset.top + (pOffset.top);
        $p = $p.parent();
    }

    var pos = {
          left: offset.left + sLeft,
          right: offset.left + w + sLeft,
          top:  offset.top + sTop,
          bottom: offset.top + h + sTop,
    }
    pos.tl = { x: pos.left, y: pos.top };
    pos.tr = { x: pos.right, y: pos.top };
    pos.bl = { x: pos.left, y: pos.bottom };
    pos.br = { x: pos.right, y: pos.bottom };
    //console.log( 'left: ' + pos.left + ' - right: ' + pos.right +' - top: ' + pos.top +' - bottom: ' + pos.bottom  );
    return pos;
}
Marcel
  • 51
  • 1
  • 1
5

BTW, if anyone want to get coordinates of element on screen without jQuery, please try this:

function getOffsetTop (el) {
    if (el.offsetParent) return el.offsetTop + getOffsetTop(el.offsetParent)
    return el.offsetTop || 0
}
function getOffsetLeft (el) {
    if (el.offsetParent) return el.offsetLeft + getOffsetLeft(el.offsetParent)
    return el.offsetleft || 0
}
function coordinates(el) {
    var y1 = getOffsetTop(el) - window.scrollY;
    var x1 = getOffsetLeft(el) - window.scrollX; 
    var y2 = y1 + el.offsetHeight;
    var x2 = x1 + el.offsetWidth;
    return {
        x1: x1, x2: x2, y1: y1, y2: y2
    }
}
SimfikDuke
  • 943
  • 6
  • 21