tags:

views:

30

answers:

2

Let's say that I have a div $container with position: relative, and a div $foo within it with position: absolute. I want to get the position of $foo relative to the container. jQuery makes this easy:

$foo.position()

which returns an object with top and left properties, specified in pixels. The problem is, this number is no longer accurate if the container is scrolled down or to the right at all. Specifically, it changes, when it shouldn't. jQuery computes position() such that it's equivalent to $foo.offset() - $container.offset() (where offset() gives the window-relative position), and $foo.offset() changes as the user scrolls around $container.

A: 
Gaby
Yep, that's right. My question was poorly phrased... let's say you don't have a handle for `$container`. What then? In other words, how would you define a `$.fn.positionInRelativeContainer()` function?
Trevor Burnham
@Trevor, added some code to find the closest relative parent
Gaby
I don't think that code will work, for 2 reasons: First, the `|| position==='absolute'` is a typo, right? Second, it will return every relative parent, not the closest one. I suppose that if there were potentially multiple nested scrolling elements, you'd want to add the `scrollLeft()` and `scrollTop()` from each. That sounds awfully computationally expensive, which is an issue if you want to redo the calculation in real-time as a user scrolls around.
Trevor Burnham
Trevor Burnham
@Trevor, indeed i forgot to add the `.eq(0)` to select the closest parent that is absolute or relative.. added it now .. In regards to multiple positioned parents, only the closest interferes with the `$foo` `position()` values..
Gaby
+1  A: 

It seems you need to take $foo.position() and then adjust is by adding $container's scrollTop() and scrollLeft().

This becomes annoying if you don't actually know what $foo's relative container is. I've resorted to writing a function (in CoffeeScript):

$.fn.container: ->
  $parent: @parent()
  if $parent.css('position') is 'relative'
    return $parent
  else
    return $parent.container()

Is there a more direct way that I'm overlooking? Or a direct way of finding an arbitrary element's container's scrollbar positions?

[Update: After reading Gaby's answer and comments, I cooked up a small jQuery plugin that goes through all of an element's parents and adds their scrollTop() and scrollLeft() to that element's position(). I haven't tested this thoroughly, so please try it and let me know if it works for you: jqPositionWithScrolling plugin

It's a little odd that position() doesn't do this automatically—I'd dare call it a bug.]

Trevor Burnham
you would have to take into account `absolute` positioned containers as well.. and also stop when you reach the body tag..
Gaby
Ah, I see. I'd forgotten that `position()` can be relative to an absolutely-positioned element as well as a relatively-positioned one. (Or a fixed-position one, for that matter. [Anything but `static`](http://www.w3schools.com/Css/css_positioning.asp).)
Trevor Burnham