jQuery *really* :visible

On a project I worked with Paul Irish on recently we found that we needed to asset whether an element was visible, but the :visible selector doesn’t always do the job.

Update: As of jQuery 1.3.2 this is no longer a problem or required. See Paul’s comment below.

The Problem with :visible

The :visible selector works fine if you’re asking whether the particular element has been set to invisible (either via the display or visibility CSS style).

However, if the element is hidden because a parent element is set to hidden, the :visible selector returns a false positive.

Solution

If you want to know whether the element is truly visible, you need to step through the parent elements to be 100% sure.

You can do this via a macro selector too:

jQuery.extend(
  jQuery.expr[ ":" ], 
  { reallyvisible : function (a) { return !(jQuery(a).is(':hidden') || jQuery(a).parents(':hidden').length); }}
);

See the working example (source)

An important note: I tried overloading the :visible selector using this new :reallyvisible and it actually breaks the show/hide functions within jQuery – so don’t go renaming it!

13 Responses to “jQuery *really* :visible”

  1. Oh my god man! You are really rocking… You’ve lots of jQ important information! Thanks you very much for sharing!

  2. arguably the :visible selector should work this way by default. nice work.

  3. Where was this solution when I needed it at DL? god knows what I ended up doing in the end but I know i had this problem a few times and never was satisfied with any of my solutions.

  4. What would be cool is if it could take absolutely positioned elements into account. For example if I have an element absolutely positioned to be under another element (with a higher Z-index – i.e. the lower element would be invisible), or even if an element was set to top:-9999em.

    The problem with this whole “reallyvisible” thing is that we get no feedback of what element is invisible:

    So if I have the following HTML:

    <div style="display:none;">
        <span>HELLO!</span>
    </div>
    

    And this JS:

    if($('span:reallyvisible').size()===0) {
        $('span').show();
    }
    

    The above JS tests whether the span is “really visible” – upon finding out that it’s not, I try making it visible, but nothing happens because it is not the span which is hidden, it’s the parent… my script has no way of knowing that – unless I hack something together.

  5. I don’t think this works correctly if !important rules are in place.

    Consider the following HTML

    <div style="display: none">Content</div>

    And then the following CSS:

    div { display: block !important; }

    This code will say that this element is hidden, which I think is a limitation of the :hidden operator in jQuery.

  6. Good job.
    Just found your post while trying to write one thing myself :)
    Thanks mate

  7. This will not work if an element is on top with a higher z-index

  8. [...] jquery *really* visible [...]

  9. This technique will be deprecated with jQuery 1.3.2:

    
    Sizzle.selectors.filters.visible = function(elem){
    	return elem.offsetWidth > 0 || elem.offsetHeight > 0;
    };
    
  10. I have 1.3.2 but IE still selects rows with display=none. The same problem does not happen with Firefox. This is how I debug:

    var e = $(“table tr”).filter(‘:visible’).map(function() { return this.style.display; }).get().join(“, “);
    alert(e);

    The alert box shows both “table-row and none”.

  11. jQuery nightly still has is(“:hidden”) not working in IE8.

    http://groups.google.com/group/jquery-dev/browse_thread/thread/f0827f3e159f2795/eff1e5b7ba16e3d0

    –DBJ

  12. extension is not working in IE8
    with my update is working:

    jQuery.extend(
    jQuery.expr[ ":" ],
    { reallyvisible : function (a) {
    return !(jQuery(a).is(":hidden") || jQuery(a).parents(":hidden").length || jQuery(a).css('display')=='none');
    }}
    );

  13. Will this approach work if my element is inside a cross-domain iframe?

Leave a Reply
Not required

CODE: Please escape code and wrap in <pre><code>, doing so will automatically syntax highlight