Find absolutely positioned element's frame of reference - javascript

I'm creating an absolutely positioned element with Javascript. This element will be used in various different contexts. So the element in relation to which it is positioned could be its parent, or any other element including the body.
I need to set the element's position (e.g. left and top) before I place it in the DOM. Is there some way to find out which element my new element will be positioned relative to? I know which element will be its direct parent. But the closest element that has a position style that is not static — the element my new element will be positioned in — might be a different element.
I considered traveling up the DOM tree and checking each parent element's position style, but that seems like a really convoluted way to do it.
So, is there a better way to find out which element is the reference frame for my absolutely positioned element's position?

Sounds like you want .offsetParent(), which will grab the first positioned parent of the element (I assume in the most efficient way possible). As per the definition of absolute positioning,
absolute
Do not leave space for the element. Instead, position it at a
specified position relative to its closest positioned ancestor if any,
or otherwise relative to the containing block. Absolutely positioned
boxes can have margins, and they do not collapse with any other
margins.
It does exactly what you're looking for.
EDIT: For a pure JavaScript solution, iterating over every parent is the only way to go. Try:
function offsetParent(elem) {
var parent = elem.parentNode;
if (window.getComputedStyle(parent).position !== 'static' || parent.tagName === 'BODY') {
return parent;
} else {
return offsetParent(parent);
}
}

There are methods, but they will require iteration through all the DOM elements, which might not be quick.
Here are possible selection of elements for you in jQuery:
$('*').filter(function(){
var position = $(this).css('position');
return position === 'absolute';
});
If you have target selector, and need to figure out if it's nested to any of parent elements, with absolute positioning, you may traverse up among all the parents with parent():
// it will return all the parent selectors, with the absolute positioning
$(targetSelector).parents().filter(function() {
var position = $(this).css('position');
return position === 'absolute';
});
See also .offsetParent(), which might be useful at some degree, but not for your purposes, as you have a bit different task. And here's why:
.offsetParent() method allows us to search through the ancestors of these elements in the DOM tree and construct a new jQuery object wrapped around the closest positioned ancestor. An element is said to be positioned if it has a CSS position attribute of relative, absolute, or fixed.
That means, it will grab the first parent element, which has any of those CSS position attributes defined: relative, absolute, or fixed. As soon as you are in need to filter out only "position:absolute;" it's not working the way you expect, and you need to take the solution I proposed several paragraphs above.

Related

How can I find a top element in the viewport?

I want to get a top element (Element Object) from the viewport of a web page with JavaScript. (If any part of the top boundary of an html element is visible on the viewport that element is within the viewport)
The approach I came up was:
Find all the elements with document.body.getElementsByTagName("*")
Check if each element is in the viewport with How can I tell if a DOM element is visible in the current viewport?
Get the element with the lowest el.getBoundingClientRect().top value from the matching elements of the step 2
If there are many element at the same level (Eg: parents and children), matching any of them would be ok.
This seems to be too much code for a small requirement. Is there a shorter approach?

How to know if my element is overflowed

I have a slider that contains N elements. Each element will by translated by N pixels when the user click on the next button. When the element is out of the wrapper div, it disappears because it is overflowed by another element.
My plugin does not use any margins, just the transform property.
I would like to know if there is a way to know if my element is out of the div. :visible does not work for my problem because the element is already visible but overflowed.
If I understand correctly, one way to do it would be to compare the position of this element to the size (width/height or both) of his parent.
With Jquery you could do it this way:
<script>
//This is the position of the right side of the element
//relative to his parent
var rightPos = $("#element").position().left + $("#element").width();
//And bottom side
var botPos = $("#element").position().top + $("#element").height();
if (rightPos > $("#element").parent().width()) {
//The element is outside the right limit of the the parent block
} else if (botPos > $("#element").parent.height()) {
//It's outside the bottom limit of the parent block
}
</script>
If it's not the parent you could then adapt this code to compare the position to the width of the correct div, preferably by using the jquery offset() method instead of position().
By determine parent width and get child width then use if condition
if($('span').width() > divWidth){
alert('Overflowed!');
// do something!
}
jsFiddle Demo
if you update your question with your html then I can update with your codes.
You could give the wrapper div the CSS property of overflow: hidden
This would mean that any elements inside of it are not visible when they leave the bounds of the wrapper.
Otherwise you could check whether your element is outside of the wrapper div using jQuery to compare the position to that of the parent.
There is a nice tool for testing if an element is visible on the screen.
Detect if a DOM Element is Truly Visible
It looks at an object and checks each of its parents to see if it’s still visible to the user.

Calculate element-position

I would like to calculate the vertical position of a <div> with jQuery.
How would I do this?
Here's an illustration describing what I mean:
I think you're looking for its offset from the top of the page, right?
$('#div').scrollTop();
If that's not it, maybe the offset would work:
$('#div').offset().top;
Okay, now that it needs to be relative to the parent, try this:
$('#div').position().top;
$('#innerDiv').position()
Get the current coordinates of the
first element in the set of matched
elements, relative to the offset
parent.
jQuery Manual for position()
I think you're looking for
$(elem).offset();
http://api.jquery.com/offset/
If you want it relative to it's container, then you're after http://api.jquery.com/position/ instead.
jQuery has several functions to help you find the offset that you are looking for.
var element = $("#your_element");
// Get the current coordinates of the first element in the set of matched elements, relative to the document.
element.offset()
// Get the closest ancestor element that is positioned.
element.offsetParent()
// Get the current coordinates of the first element in the set of matched elements, relative to the offset parent.
element.position()
// Get the current horizontal position of the scroll bar for the first element in the set of matched elements.
element.scrollLeft()
// Get the current vertical position of the scroll bar for the first element in the set of matched elements.
element.scrollTop()
For more information read about these at the jQuery offset api page.
I reckon that the jQuery API "position()" isn't what you are looking for, since it is defined as "the current position of an element relative to the offset parent" (basically it corresponds to element.offsetTop)
Therefore if you want the top position of the element relative to its parent (not necessary the offset parent), use this instead:
var top = (element.parentNode == element.offsetParent) ? element.offsetTop : element.offsetTop - element.parentNode.offsetTop;

Keep one element on top of another

I have an HTML/DOM element that I need to stay positioned above another element, regardless of where and when the target element moves.
For various (and unfortunate) reasons, I can't do this through simple CSS relative positioning. The element that I want to reposition can't be an immediate child of the parent of the target element. (It needs to be several layers up in fact, though both elements do share a common ancestor.)
I can position the element over the target element easily using jQuery's offset() functions. However, if the target element moves, the repositioned element doesn't follow. Changing the browser dimensions is one way (and the primary way I care about) this can happen; the layout changes which causes the target element's offset to change.
Here's the rough structure of my document:
<div id="common-ancestor">
<div id="to-reposition-container">
<div id="to-reposition"></div>
</div>
<div id="some-stuff-in-between"></div>
<div id="target-container">
<div id="target"></div>
<div>
</div>
I want #to-reposition to be visually placed over top of #target without changing the DOM tree. I cannot absolutely position #target outside of the natural bounds of #target-container.
I'm open to solutions that use CSS, JavaScript, and/or jQuery.
Repositioning the element the same way you did originally within a window resize event handler should work, but it certainly won't handle other cases, such as font size changes and scrolling. I don't think there's any sort of layout changing event, so if you want to catch all cases of the element's moving, you'd unfortunately have to constantly reposition in a timer event.
It's not pretty but it'll do the trick:
$(window).bind('resize',function() {/* reposition using offset */});
The better way is to use css (since that would also work in none-resize scenarios)
With the supplied markup i'd suggest setting #common-ancestor { position: relative; } and then absolutely position #to-reposition-container & #target-container on top of eachother, from there it should not be a problem for you.

JQuery - Copy dimensions and absolute position of element

I'm trying to copy a element's dimensions and the position(relative to the document) onto another element.
Ex:
var SelectedElement = $("div#MyTargetElement");
// The CopiedButEmpty element is a div with absolute position that is meant to hover/float above the selected element.
$("div#CopiedButEmpty").css("width", SelectedElement.width()).css("height", SelectedElement.height())
.css("left", SelectedElement.offset().left).css("top", SelectedElement.offset().top)
.css("marginTop", SelectedElement.css("marginTop")).css("marginLeft", SelectedElement.css("marginLeft"))
.css("marginRight", SelectedElement.css("marginRight")).css("marginBottom", SelectedElement.css("marginBottom"))
.css("paddingLeft", SelectedElement.css("paddingLeft")).css("paddingTop", SelectedElement.css("paddingTop"))
.css("paddingRight", SelectedElement.css("paddingRight")).css("paddingBottom", SelectedElement.css("paddingBottom"));
But in some cases, it still does not give me the correct position. Am I missing something? Is there any way to easily copy an elements position(relative to the document), so my element "CopiedButEmpty" can hover the element.
I wonder why you didn't chose to use jquery clone().

Categories