Check if an element IS an offsetParent - javascript

Is there a convenient way to check if an HTMLElement is an offsetParent?
I have a situation where I need to determine an element's offsetParent before it is inserted in the DOM. I can access the element's immediate parent, before insertion.
There doesn't seem to be any properties on HTMLElements that indicate whether or not it is an offsetParent.
Is there a good way to do this?

There is to my knowledge unfortunately nothing in the DOM API that does expose this information on the Element itself.
According to specs, an ancestor can be an offsetParent if
The element is a containing block of absolutely-positioned descendants
This means that not only positioned elements will qualify, but any element with a transform, or a filter property, a will-change with a value containing any of the aforementioned ones will also do.
However this behavior was not always specified this way, so it may return false positives in some browsers.
Also, it may be that in the future other CSS properties will affect what makes a containing block, or even in the present since I only got these from the tip of my head...
With that in mind, the surest is to append a test element inside your element and to check its offsetParent.
However, this will create forced reflows, so use it sporadically.
document.querySelectorAll('.container > div')
.forEach(elem => {
elem.textContent = isOffsetParent(elem) ? 'offsetParent' : 'not offsetParent';
});
function isOffsetParent(elem) {
const test = document.createElement('span');
elem.appendChild(test);
const result = test.offsetParent === elem;
elem.removeChild(test);
return result;
}
<div class="container">
<div class="is-offset-parent" style="position:relative"></div>
<div class="can-be-offset-parent" style="transform:translate(0)"></div>
<div class="can-be-offset-parent" style="filter:blur(1px)"></div>
<div class="is-not"></div>
</div>
But if you really wish some unsafe way which may need to be updated, then you could check all the properties I mentioned before using getComputedStyle(elem).

Related

Select every element that isn't a parent to any elements

I am developing a game that glitches at some point through using the CSS filter: invert(1); property. However, when you use that property on body, it makes everything position: absolute;. This is not good because I need most elements to be fixed, and everything goes to a negative top and not visible. How can I effectively get all elements in a list that isn't a parent to any other elements, but included if it has text? Any answers or other stack overflow topics would be nice!
Here is some of my code:
// In a working loop called Repeat()
if(Glitch == 1) {
document.querySelector(".ChangableStyles").innerHTML = "* {filter: invert(1)}"
} else {
document.querySelector(".ChangableStyles").innerHTML = ""
}
Edit: Since all of you are asking, the .ChangableStyles tag is a style element. The filter on everything applies when I change the innerHTML of that style tag to valid CSS styles. I don't want to be rude, but I have the .ChangableStyles thing figured out. Thank you.
You mention you already have a list of elements, but it's not clear how you're generating that list. I've gone ahead on the assumption you're wanting to "select" all elements in <body></body> that don't have any children.
You can use a combination of Array.from(), your pre-existing selection logic, and a filter() using node.childElementCount === 0 to accomplish what you describe. However on higher-complexity DOMs this will be computationally expensive, so I would implore you to re-consider your design instead of opting for this route. To be clear, this will meet your requirement of selecting ANY Node in the DOM which has no child elements ("isn't a parent to any other elements"), which includes any script, style or other "user-invisible" nodes in the body.
document.getElementById('get-elements-button').addEventListener('click', function () {
console.log(Array.from(document.body.getElementsByTagName("*")).filter(function (node) {
return node.childElementCount === 0;
}));
});
<div class="has-child-elements">
This is a child element
</div>
<div class="has-no-child-elements">
</div>
<div class="has-child-elements">
This is also a child element
</div>
<button id='get-elements-button'>Get elements with child elements →</button>

Get Parent of DOM Element Using JavaScript

I’d like to check whether a DOM element is a child of a specific DIV class regardless of the number of DIV/HTML between the element and the parent DIV. I need to use JavaScript (not jQuery). So if I had some HTML like this:
<div class="header grid-12">
<!-- many levels of divs/html -->
<div class="section">
<span id="id1">hello</span>
</div>
</div>
<div class="footer">
<!-- many levels of divs/html -->
<span id="id2">goodbye</span>
</div>
I'd want to do something like this (logically that is):
var domID = document.getElementById("id1");
if (domID a child of 'header grid-12') {
console.log('header grid-12 found');
}
I looked at parentNode children which would allow you to get all of the child nodes but I need to loop in reverse (parentnode parent if you will). I'm thinking it's much faster to start at the child and go up as opposed starting at "header grid-12" and looping through hundreds/thousands of nodes.
Thanks
The Element.closest() method returns the closest ancestor of the current element (or the current element itself) which matches the selectors given in parameter. If there isn't such an ancestor, it returns null.
source
try this,
let parent = !!document.getElementById('id1').closest('.header.grid-12');
if(parent)
{
console.log('parent found');
}
domElement.closest('selector') goes in reverse and return the nearest matching parent element. This will save you from iteratiing through all domChildElements.

Check whether element from variable has a refference in current DOM

Assume I have an element in a variable:
var element = document.getElementsByTagName("div")[0]
// here can be any kind of getting element, e. g. React ref, Chrome's devtools $0, etc.
At some point of time my markup is changing (like in SPA), and element from variable has been removed from DOM, but it still available in the element with all properties, such as parentElement, etc.
The question is: how to check, if my DOM element from element is present in DOM?
I tried to check the element.getBoundingClientRect(), and yes, there are some differences: element that removed from DOM has all the zeroes in his bounding rect. But there is one thing: element with display: none also has all the zeroes in its bounding rect, despite of it is still presents in the DOM (physically, lets say). This is not acceptable in my case, because I need to differ hidden element from removed element.
You can use contains for this purpose
function contains() {
const result = document.body.contains(element);
console.log(result);
}
const element = document.getElementById('app');
contains();
element.classList.add('hide');
contains();
element.parentNode.removeChild(element);
contains();
.hide {
display: none;
}
<div id="app">App</div>

Difference between DOM parentNode and parentElement

Can somebody explain in simple terms, what is the difference between classical DOM parentNode and newly introduced in Firefox 9 parentElement
parentElement is new to Firefox 9 and to DOM4, but it has been present in all other major browsers for ages.
In most cases, it is the same as parentNode. The only difference comes when a node's parentNode is not an element. If so, parentElement is null.
As an example:
document.body.parentNode; // the <html> element
document.body.parentElement; // the <html> element
document.documentElement.parentNode; // the document node
document.documentElement.parentElement; // null
(document.documentElement.parentNode === document); // true
(document.documentElement.parentElement === document); // false
Since the <html> element (document.documentElement) doesn't have a parent that is an element, parentElement is null. (There are other, more unlikely, cases where parentElement could be null, but you'll probably never come across them.)
In Internet Explorer, parentElement is undefined for SVG elements, whereas parentNode is defined.
Use .parentElement and you can't go wrong as long as you aren't using document fragments.
If you use document fragments, then you need .parentNode:
let div = document.createDocumentFragment().appendChild(document.createElement('div'));
div.parentElement // null
div.parentNode // document fragment
Also:
let div = document.getElementById('t').content.firstChild
console.log(div.parentElement) // null
console.log(div.parentNode) // document fragment
<template id="t"><div></div></template>
Apparently the <html>'s .parentNode links to the Document. This should be considered a decision phail as documents aren't nodes since nodes are defined to be containable by documents and documents can't be contained by documents.
Just like with nextSibling and nextElementSibling, just remember that, properties with "element" in their name always returns Element or null. Properties without can return any other kind of node.
console.log(document.body.parentElement, "is body's parent element");//<html>
console.log(document.body.parentNode, "is body's parent node"); //<html>
var html = document.body.parentElement;
console.log(html.parentElement, "is html's parent element"); //null
console.log(html.parentNode, "is html's parent node"); //document
there is one more difference, but only in internet explorer. It occurs when you mix HTML and SVG. if the parent is the 'other' of those two, then .parentNode gives the parent, while .parentElement gives undefined.

How to tell if a DOM element is displayed?

This is not to be confused with "How to tell if a DOM element is visible?"
I want to determine if a given DOM element is visible on the page.
E.g. if the element is a child of a parent which has display:none; set, then it won't be visible.
(This has nothing to do with whether the element is in the viewport or not)
I could iterate through each parent of the element, checking the display style, but I'd like to know if there is a more direct way?
From a quick test in Firefox, it looks like the size and position properties (clientWidth, offsetTop etc.) all return 0 when an element is hidden by a parent being display:none.
Using Prototype:
if($('someDiv').visible) {...}
As I'm using MochiKit, what I came up with based on Ant P's answer was:
getElementPosition('mydiv').y != 0
I can also check whether it's in the viewport (vertically) by:
y = getElementPosition('mydiv').y
(y < getViewportPosition().y + getViewportDimensions().h &&
getViewportPosition().y < y)
Incidentally this also works in IE6.
Relying on the position being 0 is brittle. You're better off writing a helper function to iterate through the parents to check their display style directly.
Here's the iterative solution -
var elementShown = function(e){
if (e == document)
return true;
if ($(e).css('display') == 'none') //or whatever your css function is
return false;
return elementShown(e.parentNode);
}
.getClientRects() will return an empty array if the element is not displayed by inheritance (display="none" from parent/ancestor element)

Categories