January, 2012
jQuery: Getting an elements position/offset relative to a parent element
Posted 13 Years Ago
Various projects I've worked on in the past have required me to get an element's position or offset that's neither relative to the document's body, nor relative to it's immediate 'position:relative' element. Up until now I've used very project specific solutions. Today, I decided to solve the problem once and for all and write my own jQuery plugin to accomplish this.
I've named the plugin offsetRelative (though I included an alias of positionRelative if you prefer that naming scheme). To call the plugin is pretty simple. You simply call the offsetRelative() function on the child element you want to get the position of and pass the 'parent' element you want the position to be relative to as the 1st parameter of the function.
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.
This would then return the top and left position of the "#child-element" relative to the "div.item-parent" which we could then use as thus:
Finally, for the actual plugin (with a few notes expalaining what's going on):
If you don't pass a 'top' element in the first parameter of the function we'll simply return jQuery's .position() function's offset (which is relative to the element's nearest reatively positioned parent element).
If the 'top' element you pass isn't a 'reatively positioned' element, meaning that element doesn't effect the viewport at which the element will be positioned, the plugin will return the offset at the element, which is to say the offset in relation to the next 'reatively positioned' element above the 'top' element we passed.
Finally, if we don't find that the 'top' element you passed exists as a parent to the child, we'll simply return the offset in relation to the document's body (the same as would happen with jQuery's .offset() function).
Let me know if you find any bugs or have any suggestions.
I've named the plugin offsetRelative (though I included an alias of positionRelative if you prefer that naming scheme). To call the plugin is pretty simple. You simply call the offsetRelative() function on the child element you want to get the position of and pass the 'parent' element you want the position to be relative to as the 1st parameter of the function.
$(child-selector).offsetRelative(parent-selector);
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.$("#child-element").offsetRelative("div.item-parent");
This would then return the top and left position of the "#child-element" relative to the "div.item-parent" which we could then use as thus:
var position = $("#child-element").offsetRelative("div.item-parent");
alert('left: '+position.left+', top: '+position:top);
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));
(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));
Functionality
Just a few notes on how the plugin will function in certain situations.If you don't pass a 'top' element in the first parameter of the function we'll simply return jQuery's .position() function's offset (which is relative to the element's nearest reatively positioned parent element).
If the 'top' element you pass isn't a 'reatively positioned' element, meaning that element doesn't effect the viewport at which the element will be positioned, the plugin will return the offset at the element, which is to say the offset in relation to the next 'reatively positioned' element above the 'top' element we passed.
Finally, if we don't find that the 'top' element you passed exists as a parent to the child, we'll simply return the offset in relation to the document's body (the same as would happen with jQuery's .offset() function).
Let me know if you find any bugs or have any suggestions.