Display: none 与 Visibility: hidden有什么区别?

2,655 阅读6分钟

  在css中,设置元素的隐藏的方式,主要有两种,一种是display:none,一种是visibility:hidden,那这两种隐藏方式的主要区别是什么呢?接下来,我将从四个方面,简单介绍一下二者的区别。

一、空间占据

  • 首先是空间占据方面,设置了display:none 样式的元素,在文档流中是不占位置的,而且,浏览器也不会解析这个元素;而设置了visibility:hidden样式的元素,在文档流中仍然占位,可以理解为,只是把透明度变成了0;

  • 举例来说:比如,我这里有2个ul,每个ul下面,有4个li,而且,对每个li都做了编号。现在我们对li3设置了display:none样式,而对li7设置了visibility:hidden属性,结果显示如下:

  • 从结果可以看出,隐藏li3后,li3在页面消失且不占位,li4将li3的位置霸占了,可以理解为彻底消失;而隐藏li7后,从视觉上来看,li7是消失了,但是li7的位置还保留着,它的位置别人不能随便占。

二、株连性

  • 株连是什么意思呢?大家应该都听过株连九族这个词,株连其实可以理解为,自己啥也没干,就被连累了。这个株连性,主要体现在父子关系的结构中。

  • 比如,我这里还是有2个ul,每个ul下面,有有4个li,而且,对每个li都做了编号。在li3和li7下面呢,又有一个div,写着“我是li3的儿子”、“我是li7的儿子”。

  • 如果这个时候,我对li3设置display:none样式,而对li7设置visibility:hidden属性,会发生什么呢?

  • 结果就是,li3和它的儿子,一起彻底消失,都不占位;而li7和它的儿子,都是视觉上消失了,但位置还在。

  • 所以可以总结出来:一旦父节点元素应用了 display:none,父节点及其子孙节点元素全部不可见,而且无论其子孙元素如何不屈地挣扎都无济于事。

三、隐藏失效

这个是什么意思呢?我们先来看一个案例:

  • 比如,我这里还是有2个div,每个div下面,有1个a标签,给了一个visibilityHidden的类名,每个a标签下面,都有一个img,引用的是相同的图片,但是第二个div里的img,给了一个visibilityVisible类名;
  • 现在,我们对visibilityHidden的类,设置一个visibility:hidden样式,对第二个div里的img的visibilityVisible设置一个visibility:visible样式,,页面显示的效果如下:这时会发生什么情况呢?
  • 结果就是,第一个a标签和下面的img都被隐藏了,而第二个a标签,虽然被设置了隐藏属性,但img设置了显示属性,所以这个img最后的结果仍然是显示出来,这就是我们提到的“隐藏失效”
  • 那如果我们对visibilityHidden的类,设置display:none样式,然后第二个div里的img的visibilityVisible设置一个display:block样式,结果是什么样呢?
  • 结果就是,子元素和父元素,一起隐藏了,子元素虽然设置了display:block企图挣扎一下,但挣扎无效。
  • 其实这个隐藏失效和前面提到的株连性很像。我觉得可以这么理解。
  • 通常情况下,display:none和visibility:hidden都有株连性,父亲隐藏,就连累孩子一起隐藏;
  • 但是,visibility有时存在隐藏失效的情况,就是如果子元素自己设置了visibility:visible显示的样式,就会发生隐藏失效的情况。

四、回流和重绘

  display:none和visibility:hidden还有一个非常大的区别就是:display:none会引起回流和重绘,而visibility:visible只会引起重绘,不会引起回流。   这里,我们就需要先了解一下什么是回流和重绘。要理解回流和重绘,首先需要看看浏览器在加载页面时发生了什么。

  • 我们都知道, 浏览器是用2个引擎来工作的,一个是渲染引擎,一个是JavaScript引擎。不同浏览器的渲染引擎是不一样的,谷歌和Safari使用的是Webkit,火狐使用的是Gecko。

  • 那当用户访问一个页面的时候呢:

    • 浏览器首先会解析html文件创建一个DOM树
    • 在创建DOM树的同时,还会解析css样式表创建一个CSS对象模型
    • 当DOM树和CSS对象模型创建好之后,浏览器会把DOM树和CSS对象模型,合成一个渲染树

  • 这个渲染树和DOM树有些类似,但不完全一样,因为DOM树只有结构,而渲染树还有样式。接下来我们可以看一下浏览器是怎么创建渲染树的。为了构建渲染树,浏览器主要完成了以下工作:

    第一,从DOM树的根节点开始遍历每个可见节点

    第二,对于每个可见的节点,找到CSSOM树中对应的规则,并应用它们。

    第三,根据每个可见节点以及其对应的样式,组合生成渲染树。

  • 可以看到,在左侧的DOM树里,有一个p标签,下面有一个span标签,右侧的CSS对象模型中,对span的样式设置了display:none,最后合成的渲染树上,这个span标签就消失了。这是合成渲染树的过程.

  • 再回到我们浏览器的工作流程中,渲染树创建完成后, 浏览器会根据渲染树进行布局,布局的流程输出的是一个盒子模型,它能精确的捕获每个节点在视图窗口的确切位置和尺寸,通常这个行为称为回流或自动重排

  • 在布局完成之后,浏览器会将渲染树的每个节点都转换为屏幕上的实际像素,这个阶段就叫做重绘节点,绘制结束后,我们的页面就会显示在屏幕上

  • 在用户访问页面的时候,浏览器会重复进行第四步和第五步,第四步是回流,第五步是重绘,所以回流必重绘,但重绘不一定会引起回流。

  • 那在什么情况下触发回流?什么情况下触发重绘呢?这里是一些会引起回流和重绘的元素。

  • 可以简单的理解为当节点发生布局的变化,比如宽高、位置、节点内容发生变化、浏览器窗口大小改变等都会触发回流和重绘行为;

  • 当一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color。则只发生重绘

  • 因此,设置display:none样式的时候,由于整个元素在页面都消失了,那页面结构就发生了改变,所以会引起回流和重绘;而设置visibility:hidden样式的时候,不会引起页面布局的变化,只相当于设置了opacity:0 ,不会引起回流的现象。