tags:

views:

595

answers:

5

I want to get the position of an element relative to the browser window (the viewport in which the page is diaplayed, not the whole page), how can this be done in javascript?

Many thanks

+1  A: 

Edit: Add some code to account for the page scrolling.

function findPos(id) {
    var node = document.getElementById(id);  
    var curtop = 0;
    var curtopscroll = 0;
    if (node.offsetParent) {
        do {
            curtop += node.offsetTop;
            curtopscroll += node.offsetParent ? node.offsetParent.scrollTop : 0;
        } while (node = node.offsetParent);

        alert(curtop - curtopscroll);
    }
}

The id argument is the id of the element whose offset you want. Adapted from a quirksmode post.

Swingley
Thanks for your answer but I think you misunderstood my question, I know how to get the top of an element relative to the page, what I'm trying to do is get the position relative to the 'viewport'(ie. the browser window, not the document)
Waleed Eissa
Sorry, your use of 'viewport' threw me. So, you're saying you want to account for the browser chrome, ie bookmarks toolbar, location bar, etc?
Swingley
No, just the window through which you see the page. If the page is scrolled this will be different than the document top, otherwise they are the same.
Waleed Eissa
Oh OK, I understand. Not sure how to do that...will edit my answer if I come up with something.
Swingley
I made the code above a little uglier but it works...use offsetParent.scrollTop
Swingley
Thanks a lot. I see prototype uses parentNode instead of offsetParent for getting the scrollTop but I don't know the reason.
Waleed Eissa
A: 

The function on this page will return a rectangle with the top, left, height and width co ordinates of a passed element relative to the browser view port.

    localToGlobal: function( _el ) {
       var target = _el,
       target_width = target.offsetWidth,
       target_height = target.offsetHeight,
       target_left = target.offsetLeft,
       target_top = target.offsetTop,
       gleft = 0,
       gtop = 0,
       rect = {};

       var moonwalk = function( _parent ) {
        if (!!_parent) {
         gleft += _parent.offsetLeft;
         gtop += _parent.offsetTop;
         moonwalk( _parent.offsetParent );
        } else {
         return rect = {
         top: target.offsetTop + gtop,
         left: target.offsetLeft + gleft,
         bottom: (target.offsetTop + gtop) + target_height,
         right: (target.offsetLeft + gleft) + target_width
         };
        }
    };
        moonwalk( target.offsetParent );
        return rect;
}
rism
A: 

You can try:

node.offsetTop - window.scrollY

It works on Opera with viewport meta tag defined.

Szere Dyeri
A: 

Just grab a copy of prototype at http://prototypejs.org/download. I believe you can get what you're looking for instantly with:

http://prototypejs.org/api/element/viewportoffset

Otherwise, go for:

http://prototypejs.org/api/document/viewport/getscrolloffsets

http://prototypejs.org/api/element/cumulativeoffset

(considering you know how to get the element's offset relative to the page, you will understand this)

EDIT By using libraries like prototype you will have the big advantage of easily coding crossbrowser compatible code. If for some reason you don't like prototype, I can recommend either jquery, or dojo

Maurice
It seems you posted your answer while I was writing mine :) Thanks a lot, I'm going to do just this
Waleed Eissa
I know it's better to use a library like JQuery to avoid the headache of such stuff, but I'm already using microsoft ajax for calling webservices from the client and don't want to add anohter library over that.
Waleed Eissa
I'm not familliar with ms ajax. Is this a library? If your web app isn't too big, I definately recommend changing over to prototype or jquery (for they are lightweight). Recoding will give you less of a headache then code that doesn't work like expected in multiple browsers.
Maurice
By the way, the page() function returns the position relative to the viewport, so there's no need to get the view port size and scroll position first to calculate the position
Waleed Eissa
I believe it can be done without a library, but it's just too much of a hassle debugging. I *really* recommend against it. Both prototype and jquery have great ajax funtionality already built in to them.
Maurice
Yes, it's a library. I'm using only one file from it, MicrosoftAjax.js. It makes it a lot easier to call webservices from the client, of course this is possible with other libraries too but it's more work. It's slightly larger than jquery, 82k, so the difference is not too large. Actually I'm using Jquery on a few pages on the site, but I'm trying to avoid using it on the pages that call the webservices to avoid having both libraries downloaded by the client. I know they should be cached but I don't think this is always the case, so, I'm trying to avoid wasting too much bandwidth
Waleed Eissa
okay, it's your decission mate. Ofcourse I don't know your project and the demands it makes. I can't help you any further with non-lib js for it will just generate too much trouble. Good luck!
Maurice
Thanks a lot, I'll continue with MicrosoftAjax for now and probably later will switch to JQuery so that I only have one lib
Waleed Eissa
A: 

Thanks for all the answers. It seems Prototype already has a function that does this (the page() function). By viewing the source code of the function, I found that it first calculates the element offset position relative to the page (i.e. the document top), then subtracts the scrollTop from that. See the source code of prototype for more details.

Waleed Eissa
Good decision. It's probably best to go with one of the major libraries as they're more likely to give the same result across browsers. If you're curious, check my my answer. The code there will do this but I have no idea how it will hold up across browsers.
Swingley