首先先介绍visibility这个CSS属性。

  visibility用于表示该元素是否显示,其取值有:

  1.   visible:设置对象可视。
  2.   hidden:设置对象隐藏。
  3.   collapse:主要用来隐藏表格的行或列,隐藏的行或列能够被其他内容是用。

  这里需要说明的是,collapse在IE6及更早的浏览器不支持,它的作用只在表格中生效,对于其他的对象,等同于display:hidden。

  介绍到这里,也许我们会有个疑问,那就是visibility:hidden与display:none有什么区别呢?他们的不同之处就是隐藏的对象是否占据位置。visibility:hidden在对象隐藏之后,它所占据的地方并不被其他元素占据。就好比一个人穿着隐身衣一样,虽然我们看不见他,但是他实际还在那里,我们仍然能摸到他,他所站的位置也不能放别的东西。但是,display:none就真的消失了,这个人就真的不存在了。因此,如果我们需要将一个容器隐藏,但是又不想让它后面的内容占据他的位置,那么visibility:hidden就派上用场了。(其实关于visibility:hidden与display:none的区别在于,前者在浏览器解析完DOM树之后,将这个容器放入渲染树进行计算和显示。而后者在生成DOM树,不会放到渲染树中进行计算和绘图)

  那么现在就有一个问题,就是如果一个元素是通过visibility:hidden隐藏了,那么我们如何通过jquery的选择器选择到它呢?我们显而易见的会想到:visible。这个语法是选择到可见的元素,再通过取反就可以了,因此,下面的代码可能是你想到的最简单的例子:



<script type="text/javascript">
$(function(){
    alert($('div:not(:visible)').length);
});
</script>
<body>
<div id="a" style="width:100px; height:100px; visibility:hidden;">11</div>
</body>



但是实际上,alert的结果是:0,也就是说,查找不可见的div没有找到。为什么会是这样呢?其实,原因是jQuery判断visible的逻辑和我们想象中的逻辑不同,我们认为这个不可见是眼睛看不到的。而jQuery的逻辑不是这样的,jquery的判断逻辑是:这个对象的offsetWidth和offsetHeight都为0才是不可见。而visibility:hidden的对象元素这两个值都是不为0的。从这看来,选择器这样写,是无法选择到这个div的。(其实这个理解起来也不难,虽然里面的内容看不到了,但是它还在这里啊,还占据着位置啊,所以必然不是不可见的)

  在jQuery的早些版本(1.3之前),上述代码是可以选择到这个div的,因为那个时候,visible的逻辑和我们想的一样,即:除了display:none和visibility:hidden之外,其他都为true。它之所以做了这个修改,很大的原因是效率问题。我们可以在官方的doc上找到原文:

  • 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.

详情可以参考全文:http://docs.jquery.com/Release:jQuery_1.3.2#:visible.2F:hidden_Overhauled

  根据上面的原理,我们其实可以做一个小小的修改,如果我们把div的样式改成:width:0; height:0;去掉visibility:hidden,我们刷新下看看,alert弹出了1,也就是说,它仍然能找到这个div,与display:none与visibility:hidden无关了,而且div中的“11”还显示在页面上呢,但是,jquery认为它是不可见的。

  说了这么多,那么解决办法呢,既然visible的判断的逻辑已经和我们想象的有偏差,那么我们可以通过重新将老版本的jquery逻辑添加进来。方法有很多,我这里给出一个用filter方法实现的代码:


$('div').filter(function(){
   return ($(this).css('visibility') == 'hidden' || $(this).css('display') == 'none');
});


上面的代码就可以实现visibility:hidden的选择了。当然,如果我们常用这个方法的话,可以把它封装一下。