[TOC]

CSS中隐藏元素属性opacity、visibility、display对比分析

1. 说明

opacity 用来设置透明度。

display 定义建立布局时元素生成的显示框类型。

visibility 用来设置元素是否可见。

opacity、visibility、display 这三个属性分别取值 0、hidden、none 都能使元素在页面上看不见,但是他们在方方面面都还是有区别的。

opacity: 0 visibility: hidden display: none
是否占据页面空间
子元素设置该属性其他值是否继续显示 不显示 显示 不显示
自身绑定的事件是否能触发 能触发 不能触发 不能触发
是否影响遮挡住的元素触发事件 影响 不影响 不影响
属性值改变是否产生回流(reflow) 不产生 不产生 产生
属性值改变是否产生重绘(repaint) 不一定产生 产生 产生
该属性是否支持transition 支持 支持 不支持

2. 是否占据页面空间对比

使用 opacity 和 visibility 属性时,元素还是会占据页面空间的,而使用 display 属性时,元素不占据页面空间。

代码:

<html lang="en"> <!-- http://js.jirengu.com/palal/5/edit -->
 <head>
  <meta charset="UTF-8">
  <style>
    div { width: 100px; height: 100px; }
    .box {
      border: 1px solid; width: 150px;
      height: 230px; display: inline-block;
    }
    .yellow{ background:yellow; }
    .red{ background:red; }
    .blue {background:blue; opacity:0;}
    .green {background: green; visibility:hidden;}
    .other {background: #3472f3; display:none;}
  </style>
 </head>
 <body>
   <div class="box">
     正常的时候
     <div class="yellow"></div> <div class="red"></div>
   </div>
   <div class="box">
     opacity:0;
     <div class="blue"></div> <div class="red"></div>
   </div>
   <div class="box">
     visibility:hidden;
     <div class="green"></div> <div class="red"></div>
   </div>
   <div class="box">
     display:none;
     <div class="other"></div> <div class="red"></div>
   </div>
 </body>
</html>

3. 对子元素的影响

如果子元素什么都不设置的话,都会受父元素的影响,和父元素的显示效果一样。

如果子元素设置的值和父元素不一样时:

使用 opacity 和 display 属性时,父元素对子元素的影响很明显,子元素设置的 opacity 和 display 属性是不起作用的,显示的效果和父元素一样,而使用 visibility 属性时,子元素如果设置为 visibility:visible; 并没有受父元素的影响,可以继续显示出来。

代码:

<!doctype html> <!-- http://js.jirengu.com/focitecila/7/edit -->
<html lang="en">
 <head>
  <meta charset="UTF-8">
   <style>
       div {border: 1px solid;}
      .box { height: 130px; width: 130px; padding: 5px; display: inline-block; }
      .father { width:100px; height:100px;padding: 5px; background: yellow; }
      .son { width:50px; height:50px; background: blue; }
   </style>
 </head>
 <body>
   <div class="box">
     正常
     <div class="father">
       <div class='son'></div>
     </div>
   </div>
   <div class="box">
     opacity 测试
     <div class="father" style="opacity:0;">
       <div class='son'  style="opacity:1;"></div>
     </div>
   </div>
   
   <div class="box">
     visibility 测试
     <div class="father" style="visibility:hidden;">
       <div class='son'  style="visibility:visible;"></div>
     </div>
   </div>
   <div class="box">
     display 测试
     <div class="father" style="display:none;">
       <div class='son'  style="display:block;"></div>
     </div>
   </div>
 </body>
</html>

4. 自身绑定的事件是否能继续触发

这里的绑定事件是指用户在页面操作触发的事件。

使用 display 属性的话,元素不仅看不见,而且也不占据页面空间,所有不会触发事件。

总的来说,使用 visibility 和 display 属性,自身的事件不会触发,而使用 opacity 属性,自身绑定的事件还是会触发的。

代码:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <style>
    div {border: 1px solid;}
    .box { height: 130px; width: 130px; padding: 5px; display: inline-block; }
    .button { cursor: pointer; }
  </style>
</head>
<body>
  <div class="box">
    正常
    <div class="button" onmouseenter="alert(0)">
      点击我
    </div>
  </div>
  <div class="box">
    opacity 测试
    <div class="button" onmouseenter="alert(0)" style="opacity:0;">
      点击我
    </div>
  </div>
  <div class="box">
    visibility 测试
    <div class="button" onmouseenter="alert(0)" style="visibility:hidden;">
      点击我
    </div>
  </div>
</body>
</html>

5. 是否影响其他元素触发事件

总结:visibility 和 display 属性是不会影响其他元素触发事件的,而 opacity 属性 如果遮挡住其他元素,其他的元素就不会触发事件了。

如下图:

1、在opacity 测试部分,黄色块div元素设置 opacity:0;,通过定位,遮挡住了 蓝色的p元素,当鼠标移到蓝色p元素上时,并没有触发蓝色p元素的事件。

2、在visibility 测试部分,黄色块div元素设置 visibility:hidden;,通过定位,虽然遮挡住了 蓝色的p元素,但是当鼠标移到蓝色p元素上时,还是触发了蓝色p元素绑定的事件。

3、display 属性就不举例子了,因为他不会占据页面空间,也就不会遮挡其他元素,就不会影响其他元素触发事件了。

代码:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <style>
    .box { height: 200px; width: 250px; padding: 5px; display: inline-block; border: 1px solid; }
    .red{ width:200px; height:20px; background:red; position:relative; }
    .yellow{ position:absolute; top:0; left:0; width:100px; height:150px; background:yellow;}
    .blue{ width:100px; height:100px; background:blue; }

    .opacity .yellow { opacity:0; }
    .opacity .red:hover .yellow { opacity:1;   }
    
    .visibility .yellow { visibility: hidden; }
    .visibility .red:hover .yellow { visibility: visible; }
  </style>
</head>
<body>
  <div class="box opacity">
    opacity 测试
    <div class='red'>
      <div class='yellow'></div>
    </div>
    <p class='blue' onmouseenter=alert(0)></p>
  </div>
  <div class="box visibility">
    visibility 测试
    <div class='red'>
      <div class='yellow'></div>
    </div>
    <p class='blue' onmouseenter=alert(0)></p>
  </div>
</body>
</html>

6. 是否产生回流(reflow)

回流

当页面中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(也有人会把回流叫做是重布局或者重排)。 每个页面至少需要一次回流,就是在页面第一次加载的时候。

dispaly 属性会产生回流,而 opacity 和 visibility 属性不会产生回流。

7. 是否产生重绘(repaint)

重绘

当页面中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的时候,比如background-color。则称为重绘。

dispaly 和 visibility 属性会产生重绘,而 opacity 属性不一定会产生重绘。

元素提升为合成层后,transform 和 opacity 不会触发 repaint,如果不是合成层,则其依然会触发 repaint。 在 Blink 和 WebKit 内核的浏览器中,对于应用了 transition 或者 animation 的 opacity 元素,浏览器会将渲染层提升为合成层。 也可以使用 translateZ(0) 或者 translate3d(0,0,0) 来人为地强制性地创建一个合成层。

opacity 例子代码:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <style>
    p { transition: 1s; padding: 10px; border: 1px solid; width: 300px;}
  </style>
</head>
<body>
  <div id="one">重绘 repaint</div>
  <p id="two">重绘 repaint transition</p>
  <script>
    var flag = false;
    setInterval(function () {
      flag = !flag;
      one.style.opacity = flag ? 0 : 1;
    }, 1000);
    var flag2 = false;
    setInterval(function () {
      flag2 = !flag2;
      two.style.opacity = flag2 ? 0 : 1;
    }, 1000)
  </script>
</body>
</html>

首先打开Chrome DevTools 的 Rendering 来检查看效果:

chorome浏览器打开DevTools -> 右上角三个点 -> More tools -> Renddering -> 再出现的界面中 勾选 Paint flashing

然后页面效果:

通过查看效果,在没有加 transition 的元素中有高亮显示,加上 transition 后就没有 高亮显示了,这时候 opacity 不会触发重绘。

实际上透明度改变后,GPU 在绘画时只是简单的降低之前已经画好的纹理的 alpha 值来达到效果,并不需要整体的重绘。不过这个前提是这个被修改的 opacity 本身必须是一个图层,如果图层下还有其他节点,GPU 也会将他们透明化。

注意:回流必将引起重绘,而重绘不一定会引起回流。

8. 是否支持transition

opacity 是支持 transition的。

visibility 也是支持 transition 的, visible 过渡到 hidden,看上去不是平滑的过渡,而是进行了一个延时。而 hidden 过渡到 visible ,则是立即显示,没有延时。

display 不仅不支持transition,它还会使 transition 失效。这是因为display:none; 的元素,是不会渲染在页面上的,而 transition 要起作用,元素必须是已经渲染在页面上的元素。

opacity 和 visibility 例子代码:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <style>
    div { transition: 1s; padding: 10px; border: 1px solid; width: 300px; margin-bottom: 20px;}
  </style>
</head>
<body>
  <div id="one">visibility transition 测试</div>
  <div id="two">opacity transition 测试</div>
  <div id="three">display transition 测试</div>
  <script>
    var flag = false;
    setInterval(function () {
      flag = !flag;
      one.style.visibility = flag ? 'hidden' : 'visible';
    }, 2000);
    var flag2 = false;
    setInterval(function () {
      flag2 = !flag2;
      two.style.opacity = flag2 ? 0 : 1;
    }, 1000)
    var flag3 = false;
    setInterval(function () {
      flag3 = !flag3;
      three.style.display = flag3 ? 'none' : 'block';
    }, 1000)
  </script>
</body>
</html>

效果:

参考资料

https://segmentfault.com/a/1190000015116392

Last Updated: 3/17/2021, 8:46:40 AM