How to tell if a DOM element is displayed? - javascript

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)

Related

Determine what CSS selectors are been applied to an element

Is there a way do determine if a selector is currently been applied to an given element?
I know it´s possible to iterate over all CSS selectors, and test if each one is applicably or not. But I´m not sure if this is the way that Firebug and other inspector do it.
EDIT:
I need a way to do it dynamically, with JS.
You can check if an element instance is matched by a selector by using document.querySelectorAll and Array.prototype.indexOf:
function elementMatchesSelector(element, selector) {
return Array.prototype.indexOf.call(document.querySelectorAll(selector), element) > -1;
}
Of course this only works for modern browsers that support the aforementioned methods.
Alternatively you can use Element.matches:
function elementMatchesSelector(element, selector) {
var fn;
if (!element) {
return false;
}
fn = element.matches || element.mozMatchesSelector || element.msMatchesSelector || element.webkitMatchesSelector;
if (fn) {
return fn.call(element, selector);
}
return false;
}
In Firebug, you can look at the Computed Side Panel. For any given DOM element, it shows the CSS styles applied (even those applied via JavaScript). It also depicts the styles that were overridden. From the docs:
The Computed Side Panel shows all CSS style values calculated by the user agent while interpreting the given CSS information for the selected node inside the HTML Panel.
What about using getComputedStyle()
MDN Link

How to get the parent node of an element when the parent has siblings?

Please take a look at the snippet below:
<div>
<div></div>
<div><!-- my target node -->
<div><!-- not my target node -->
<img /><!-- my source node -->
</div>
</div>
</div>
As you can see the img-elment has two enclosing divs. I want the first of those two enclosing divs to be considered the "real" parent (the one I need to find) of the img-elment because it has a brother div before so the search ends and the brother div and the outer enclosing div are ignored.
In the case there are no siblings at all, the outer div has to be yielded; in the case the element is not enclosed, the element itself has to be yielded.
I just would like to know how to target the element as I explained via JavaScript.
So it sounds like you want the first ancestor that has siblings elements. If so, you can do it like this:
var parent = img.parentNode;
while (parent && !parent.previousElementSibling && !parent.nextElementSibling) {
parent = parent.parentNode;
}
Or perhaps more appropriately written as a do-while loop:
do {
var parent = img.parentNode;
} while (parent && !parent.previousElementSibling && !parent.nextElementSibling);
So the loop will end when it finds one with at least one sibling element, or when it runs out of ancestors.
If you know if the sibling comes before or after the parent, you can just test for one or the other.
Also note that you'll need a shim for the ***ElementSibling properties if you're supporting legacy browsers.
You can make a function that will do this:
function prevElement(el) {
while ((el = el.previousSibling) && el.nodeType !== 1) {
// nothing needed here
}
return el;
}
function nextElement(el) {
while ((el = el.nextSibling) && el.nodeType !== 1) {
// nothing needed here
}
return el;
}
Then use the functions like this:
do {
var parent = img.parentNode;
} while (parent && !prevElement(parent) && !nextElement(parent));
If you don't know how many levels up the parent element is, it will be difficult to select it using methods like element.getParent alone. However, you CAN iterate through parent nodes until the node you're looking at has siblings and is the child of a body element. Let's assume that your img tag is referred to by imgNode.
function getParentWithSiblings(imgNode) {
for( ; n; n = imgNode.parentNode) {
if (n.nextSibling && n.parentNode.tagName == 'body') {
return n;
}
}
}
In the code above, we progressively iterate through the parents of the image node. At each iteration, we check whether the current node (some parent of the img node) has a sibling and is the child of a body tag.
Just in case you're curious, here's how you might implement user1689607's answer using jQuery.
function getAncestorWithSiblings(element) {
var ancestor = element.parent();
while (ancestor && ancestor.siblings().length === 0) {
ancestor = ancestor.parent();
}
return ancestor;
}
Whether it makes sense to use this library for your purposes depends on a great deal of context we don't have. As others have rightfully pointed out, you don't need jQuery to solve this problem, and it may be an unnecessarily heavyweight solution. That said, it can be a very useful library and is certainly worth your consideration if you weren't aware of it or hadn't already looked into it.

Is there a CSS :visible (scroll) selector?

I want to change the style of visible elements using CSS only. Is there a selector that does it? It needs to work with Chrome and Firefox only. (I am building an extension / addon)
If there isn't, is there a way to change the style of visible elements with a light javascript?
Visible within the current scroll position. An element can be out of the scroll vision, or partially visible.
There is no standard pure CSS rule for assessing visibility.
As others have said, jQuery (if you wanted to use jQuery) has both a CSS selector extension :visible and the ability to execute .is(':visible') on any given jQuery object to get the computed style on any given DOM element with .css("display") or .css("visibility").
It's not particularly simple in plain javascript to determine if an object is visible because you have to get the computedStyle (to take into account all possible CSS rules that might be affecting the element) and you have to make sure no parent objects are hidden causing the child element to be hidden. This is a function I have in my own personal library:
//----------------------------------------------------------------------------------------------------------------------------------
// JF.isVisible function
//
// Determines if the passed in object is visible (not visibility:hidden, not display: none
// and all parents are visible too.
//
// Source: http://snipplr.com/view/7215/javascript-dom-element-visibility-checker/
//----------------------------------------------------------------------------------------------------------------------------------
JF.isVisible = function(obj)
{
var style;
if (obj == document) return true;
if (!obj) return false;
if (!obj.parentNode) return false;
if (obj.style) {
if (obj.style.display == 'none') return false;
if (obj.style.visibility == 'hidden') return false;
}
//Try the computed style in a standard way
if (window.getComputedStyle) {
style = window.getComputedStyle(obj, "")
if (style.display == 'none') return false;
if (style.visibility == 'hidden') return false;
} else {
//Or get the computed style using IE's silly proprietary way
style = obj.currentStyle;
if (style) {
if (style['display'] == 'none') return false;
if (style['visibility'] == 'hidden') return false;
}
}
return JF.isVisible(obj.parentNode);
};
There is no pure CSS way of doing this. As Kirean's comment already said, why would you want to style visible elements only? Invisible elements won't show their styling anyway. If you don't want the invisible element to take up space (aka, laid out), you should use display: none;
If you REALLY want a selector to select the visible elements, you could do what Widor suggested and use jQuery. You could first use jQuery to first select the visible elements, add a class to them, then use CSS to select the elements by that class.
$('div:visible').addClass('visibleElement');
.visibleElement {
color: red;
}
There is no Way to select invisible elements, using pure CSS
http://www.w3.org/TR/selectors/
However, if you have a class name or other selector, using jquery you can do something like the following
jQuery(selector).each(function(){
Var $this=$(this);
if ($this.css('visibility')==='hidden')
//set your style
})
Edit: after your edit, there is definitely no way of selecting what is within the viewport with CSS alone. It is a context free language of sorts.
However, you can always fool around with an elements offset position with jquery and determine if it's within the current viewport(window.scrollposition or something similar). This type of solution gets messy quickly, though.
This looks like a :visible selector to me:
http://api.jquery.com/visible-selector/
EDIT: Saw your javascript tag before your 'no CSS' caveat.
But this is a CSS selector of sorts.

jQuery parent of a parent

I am currently trying to find the parent of a parent of an element. I have a link being clicked that is in a <td>, and I'd like to get the <tr> object.
Why wont "$(this).parent().parent()" work? What will?
Thanks,
Brendan
Edit: It appears an error in my syntax was throwing the whole thing off. "$(this).parent().parent()" does in fact work, but I wound up going with $(this).closest('tr')" because it seems like the most efficient solution.
The best way would probably be using closest:
$(this).closest('tr');
Check out the documentation:
Closest works by first looking at the current element to see if it matches the specified expression, if so it just returns the element itself. If it doesn't match then it will continue to traverse up the document, parent by parent, until an element is found that matches the specified expression. If no matching element is found then none will be returned.
It should work. You can also try $(this).parents(tag) , where tag is the tag you want to find.
For example:
$(this).parents("tr:first")
Will find the closest tr "up the chain".
That should work... you might try
$(this).parents(':eq(1)');
The .parents(selector) says get all ancestors that match the selector
and the :eq(1) says find the oneth (zero-indexed, so the second) element in the list
This snippet has performed for me in the past:
$(this).parent().parent();
Post some code for us to see if there might be another problem somewhere...
also try
$(this).closest('div.classname').hide();
If you have any sort of id/class for the parent, you can use parents() but that will give you all parents up to the < body > unless you filter() or stop it some other way like
$(this).parents('.myClass');
Hope this helps someone :)
Try wrapping the $(this).parent() into an jQuery object like $($(this).parent()) I often find the need to do this to make sure I have a valid jquery object. From there you should be able to get a hold of the parents parent, or using the prev() perhaps.
var getParentNode = function(elem, level) {
level = level || 1;
for (var i = 0; i < level; i++) {
if (elem != null) {
elem = elem.parentNode;
}
}
return elem;
}
.closest() is not always best option specially when you have same element construct.
<div>
<div>
<div>
</div>
</div>
</div>
You can do parent of a parent and it's very easy:
var parent = $('.myDiv').parent();
var parentParent = $(parent).parent();
var parentParentParent = $(parentParent).parent();
etc.

Determine if collection of elements are visible using JQuery like $(".someClass")

I have a collection of elements on my page, and I want to see if they are visible or not currently.
So:
$(".someClass")
How can I loop through and figure this out? because if it is visible, i have to fire another function.
$(".someClass").each(function(){
if($(this).is(":visible")){
//item is visible: do something
}
});
how about that?
$(".someClass:visible")
will return the visible ones.
What you could do:
$(".someClass").each(function(x) { if ( x.style.display != "none" && x.style.visibility != "hidden" ) { your_function(); } });
where your_function() is the name of your function.
All solutions in terms of $('.someClass').is(':visible') are unreliable. All it tells us is if a particular element has a styling of display:none or visibility:hidden. This is not the same as whether an element is visible!
Consider a situation like this:
<div style="display:none;"><div class="someClass"></div></div>
Everybody can see that the element designated by $('.someClass') is invisible. But $('.someClass').is(':visible') will return true!
The only water-proof solution is to not only check for is(':visible') on the $('.someClass'), but on all of its parent elements as well. Only if for none of the parents holds that is(':visible') === false, we can conclude that $('.someClass') is actually visible.

Categories