Firefox, query selector and the visible pseudo selector
Asked Answered
S

6

22

Is there anyway to use a pseudo selector with Firefox's querySelector() or querySelectorAll() functions to detect visibility? In particular I want to be able to do something like this:

elem.querySelector('#list .list-item:visible');
elem.querySelector('#section .sub-section:visible .title');

No need to worry about browser inconsistencies or other implementation, just Firefox. Thanks!

EDIT: Visible is defined by display not being none and visibility not being hidden.

Stoppage answered 14/11, 2012 at 22:38 Comment(2)
What's your definition of "visibility"?Fanaticize
The DOM element's display set to block would work, but ideally it would also check that visibility is set to visible.Stoppage
S
12

No, there isn't. The CSS specification doesn't define a :visible (or related) selector, and AFAIK Firefox doesn't implement non-standard pseudo selectors.

If you'd like to implement this yourself, note how jQuery implements its :visible selector:

In jQuery 1.3.1 (and older) an element was visible if its CSS "display" was not "none", its CSS "visibility" was not "hidden", and its type (if it was an input) was not "hidden". In jQuery 1.3.2 an element is visible if its browser-reported offsetWidth or offsetHeight is greater than 0.

Source: http://docs.jquery.com/Release:jQuery_1.3.2#:visible.2F:hidden_Overhauled

Siliceous answered 14/11, 2012 at 22:46 Comment(3)
That's what I feared...to bad. I understand it isn't a useful pseudo selector for CSS, but it would be really helpful in Javascript.Stoppage
the jQuery implementation doesn't really work well at all for detecting the css visibility property as visibility: hidden will take space on the documentScribbler
And on philosophical level perhaps that is the correct implementation...depends on what you consider visible...if it is taking space on the page then there is some room to argue that the element is "visible".Stoppage
S
24

Since there is no native implimentation of the :visible pseudo selector I decided to use CSS classes to hide and show my elements, thus allowing to simply just check for the class name instead of visibility. Here is what my selector looks like now:

elem.querySelector('#list .list-item:not(.hidden)');

Now in 2016 we can also use the hidden html5 attribute, so this selector would work too:

elem.querySelector('#list .list-item:not([hidden])');
Stoppage answered 14/11, 2012 at 23:19 Comment(4)
is this still the best way in 2015?Marjoriemarjory
I believe so, :visible is not and will probably never be part of the css specification.Stoppage
A more popular way to do this in 2016 is to use the new hidden html5 global attribute. It is not fully backward compatible, so be careful. Here is Mozilla's docs developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/…Stoppage
@Marjoriemarjory the hidden attribute sets the elements display to none. So no, it does not consider opacity.Stoppage
D
16

For finding elements that are not display:none the CSS selector equivalent to :visible is

:not([style='display:none'])

You could do the same for visibility:hidden and then chain :not() selectors if you need to.

Here's a fiddle.

Edit: Be careful with spaces and other punctuation. If you later manipulate these elements with JQuery and hide(), for instance, and need to call the same function, then you will need to chain :not([style="display: none;"]) to your CSS selector.

Dnepropetrovsk answered 18/1, 2019 at 19:7 Comment(0)
S
12

No, there isn't. The CSS specification doesn't define a :visible (or related) selector, and AFAIK Firefox doesn't implement non-standard pseudo selectors.

If you'd like to implement this yourself, note how jQuery implements its :visible selector:

In jQuery 1.3.1 (and older) an element was visible if its CSS "display" was not "none", its CSS "visibility" was not "hidden", and its type (if it was an input) was not "hidden". In jQuery 1.3.2 an element is visible if its browser-reported offsetWidth or offsetHeight is greater than 0.

Source: http://docs.jquery.com/Release:jQuery_1.3.2#:visible.2F:hidden_Overhauled

Siliceous answered 14/11, 2012 at 22:46 Comment(3)
That's what I feared...to bad. I understand it isn't a useful pseudo selector for CSS, but it would be really helpful in Javascript.Stoppage
the jQuery implementation doesn't really work well at all for detecting the css visibility property as visibility: hidden will take space on the documentScribbler
And on philosophical level perhaps that is the correct implementation...depends on what you consider visible...if it is taking space on the page then there is some room to argue that the element is "visible".Stoppage
S
7

Using plain javascript, you could also emulate jQuery behaviour easily, turning your querySelector results into an array, and filtering it:

Array.prototype.slice.call(document.querySelectorAll('your selector'))

That creates a plain array with the results of your selector, that you can filter as:

.filter(function (item,index) { return item.style.display!="none" } );

or even the rest of jquery conditions (item.style.visibility != "hidden" && item.style.opacity > 0 && ...).

As a one liner:

Array.prototype.slice.call(document.querySelectorAll('your selector')).filter(function (item,index) { return item.style.display!="none" } );
Skuld answered 18/10, 2017 at 10:52 Comment(0)
I
3

Checking if element is visible, supports on all major browsers:

jQuery:

$('.list-item').is(':visible');

Vanilla JS:

function isVisible(elem) {return elem.offsetWidth > 0 || elem.offsetHeight > 0 || elem.getClientRects().length > 0; }
Ideologist answered 18/4, 2016 at 17:7 Comment(3)
Are you sure those two examples are equivalent in all versions of jQuery?Stoppage
@Stoppage They are equivalent in the latest version of jQuery, I didn't check (and therefore never mentioned) earlier versions of jQuery regarding this method.Ideologist
I see, please don't take this the wrong way, but when you've been doing this for over a decade you stop assuming a mention means the "latest version". Think about what someone else reading your answer in 2 years time would think, jQuery3?Stoppage
M
0

You can use the offsetParent value to determine if the element is visible or not.

let parent = document.getElementById('parent');
let allSubChildren = parent.querySelectorAll('.sub-children');

let visibleChildren = Array.prototype.slice.call(allSubChildren).filter(function (item, index) {
    console.log('Element "' + item.textContent + '" is ' + (item.offsetParent !== null ? 'visible' : 'hidden'));
    return item.offsetParent !== null;
  }
);

console.log(visibleChildren);
.none {
  display: none;
}

.hidden {
  visibility: hidden;
}
<p><b>item.offsetParent</b> returns <b>null</b> if the element or any parent is not displayed.</p>
<em>Check the console</em>

<div id="parent">
  <div class="children">
    <div class="sub-children">visible</div>
  </div>
  <div class="children hidden">
    <div class="sub-children">visibility hidden doesn't work</div>
  </div>
  <div class="children none">
    <div class="sub-children">display none</div>
  </div>
  <div class="children">
    <div class="sub-children">also visible</div>
  </div>
  <div class="children">
    <div class="sub-children none">also display none</div>
  </div>
</div>

<div id="result">

</div>
Mercurochrome answered 17/4, 2020 at 7:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.