为了账号安全,请及时绑定邮箱和手机立即绑定

投稿004期 | CSS中用 opacity、visibility、display 属性将 元素隐藏 的 对比分析

标签:
Html/CSS

说明

opacity 用来设置透明度
display 定义建立布局时元素生成的显示框类型
visibility 用来设置元素是否可见。
opacity、visibility、display 这三个属性分别取值 0、hidden、none 都能使元素在页面上看不见,但是他们在方方面面都还是有区别的。

是否占据页面空间

举个例子

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <style>
    .yellow{
        width:100px;
        height:100px;
        background:yellow;
    }
    .red{
        width:100px;
        height:100px;
        background:red;
    }
  </style>
 </head>
 <body>
    <div class="yellow"></div>
    <div class="red"></div>
 </body>
</html>

最开始的样子

图片描述

黄色块div元素 使用 opacity:0;

图片描述

黄色块div元素 使用 visibility:hidden;

图片描述

黄色块div元素 使用 display:none;

图片描述

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

对子元素的影响

如果子元素什么都不设置的话,都会受父元素的影响,和父元素的显示效果一样,我们就来举例看看,如果子元素设置的值 和 父元素设置的值不同会有什么效果。
例子 (opacity属性)

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <style>
	.yellow{
		width:100px;
		height:100px;
		background:yellow;
		opacity:0;  /* 父元素的 opacity属性取值为0 */
	}
	.blue{
		width:50px;
		height:50px;
		background:blue;
		opacity:1;   /* 子元素的 opacity属性取值为1 */
	}
  </style>
 </head>
 <body>
	<div class="yellow">
		<div class='blue'></div>
	</div>
 </body>
</html>

图片描述

例子 (visibility属性)

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <style>
	.yellow{
		width:100px;
		height:100px;
		background:yellow;
		visibility:hidden;  /* 父元素的 visibility属性取值为hidden */
	}
	.blue{
		width:50px;
		height:50px;
		background:blue;
		visibility:visible;  /* 子元素的 visibility属性取值为visible */
	}
  </style>
 </head>
 <body>
	<div class="yellow">
		<div class='blue'></div>
	</div>
 </body>
</html>

图片描述

例子 (display属性)

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <style>
	.yellow{
		width:100px;
		height:100px;
		background:yellow;
		display:none;  /* 父元素的 display属性取值为none */
	}
	.blue{
		width:50px;
		height:50px;
		background:blue;
		display:block;  /* 子元素的 display属性取值为block */
	}
  </style>
 </head>
 <body>
	<div class="yellow">
		<div class='blue'></div>
	</div>
 </body>
</html>

图片描述

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

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

这里说的触发事件,是指用户人为的触发的事件,不包括使用 JavaScript 模拟触发的事件。
例子 (opacity属性)

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <style>
	.yellow{
		width:100px;
		height:100px;
		background:yellow;
		opacity:0;
	}
 
  </style>
 </head>
 <body>
	<div class="yellow" onmouseenter="alert(0)"></div>
 </body>
</html>

图片描述

例子 (visibility属性)

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <style>
	.yellow{
		width:100px;
		height:100px;
		background:yellow;
		visibility:hidden;
	}
 
  </style>
 </head>
 <body>
	<div class="yellow" onmouseenter="alert(0)"></div>
 </body>
</html>

图片描述

使用 display:none; 就不用举例子了,因为使用 display 属性的话,元素不仅看不见,而且也不占据页面空间,所有不会触发事件。

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

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

例子(opacity属性)

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <style>
       .red{
         width:400px;
         height:40px;
         background:red;
         position:relative;
       }
       
       .yellow{
        position:absolute;     
        top:0;
        left:0;
        width:200px;
        height:300px;
        background:yellow;
        opacity:0;            
       }
        
       .blue{
         width:200px;
         height:200px;
         background:blue;
       }
       .red:hover .yellow{
         opacity:1;          
       }
  </style>
 </head>
 <body>
      <div  class='red'>
         <div class='yellow'></div>
      </div>

      <p  class='blue' onmouseenter=alert(0)></p>
 </body>
</html>

图片描述

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

例子(visibility属性)

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <style>
       .red{
         width:400px;
         height:40px;
         background:red;
         position:relative;
       }
       
       .yellow{
        position:absolute;     
        top:0;
        left:0;
        width:200px;
        height:300px;
        background:yellow;
        visibility:hidden;          
       }
        
       .blue{
         width:200px;
         height:200px;
         background:blue;
       }
       .red:hover .yellow{
         visibility:visible;       
       }
  </style>
 </head>
 <body>
      <div  class='red'>
         <div class='yellow'></div>
      </div>

      <p  class='blue' onmouseenter=alert(0)></p>
 </body>
</html>

图片描述

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

和上边一样,display 属性就不举例子了,因为他不会占据页面空间,也就不会遮挡其他元素,就不会影响其他元素触发事件了。
所以,visibility 和 display 属性是不会影响其他元素触发事件的,而 opacity 属性 如果遮挡住其他元素,其他的元素就不会触发事件了。

是否产生回流(reflow)

回流

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

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

是否产生重绘(repaint)

重绘

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

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

举个例子

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
</head>
<body>
	<div id="target">重绘 repaint</div>

	<script>
		var flag = false;
		setInterval(function () {
			flag = !flag;
			target.style.opacity = flag ? 0 : 1;
		},1000)
	</script>
</body>
</html>

我们可以用 Chrome DevTools 的 Rendering 来看看,
先打开 Rendering

图片描述

把第一个选项勾选,这个选项会 高亮显示需要重绘的区域。

图片描述

看看效果

图片描述

改改代码,增加上个 transition

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <style>
    div{
        transition:1s;
    }
  </style>
</head>
<body>
	<div id="target">重绘 repaint</div>

	<script>
		var flag = false;
		setInterval(function () {
			flag = !flag;
			target.style.opacity = flag ? 0 : 1;
		},1000)
	</script>
</body>
</html>

再看看效果

图片描述

加上 transition 后就没有 高亮显示了,这时候 opacity 不会触发重绘。

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

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

是否支持transition

opacity 是支持 transition的,一般淡入淡出的效果就是这样实现的。

图片描述

visibility 也是支持 transition 的。

visibility: 离散步骤,在0到1数字范围之内,0表示“隐藏”,1表示完全“显示”

visibility : hidden; 可以看成 visibility : 0;
visibility : visible; 可以看成 visibility : 1;

只要 visibility 的值大于0就是显示的,所以
visibility:visible 过渡到 visibility:hidden,看上去不是平滑的过渡,而是进行了一个延时。

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <style>
  .blue{
	width:200px;
	height:200px;
	background:blue;
	transition:1s;
	visibility:visible;
  }
  .blue:hover{
	visibility:hidden;
  }
  </style>
 </head>
 <body>
	<div class='blue'></div>
 </body>
</html>

图片描述

而如果 visibility:hidden 过渡到 visibility:visible ,则是立即显示,没有延时。
注意
上面这个例子只能是从 visibility:visible 过渡到 visibility:hidden,不能从 visibility:hidden 过渡到 visibility:visible
当元素是 visibility:hidden; 时,自身的事件不会触发,所以像上面这个例子中,直接在蓝色块div元素 上加 hover 事件,要去将自身的 visibility:hidden 过渡到 visibility:visible 是不会起作用的。
但是在其他元素上加事件,来将该元素的 visibility:hidden 过渡到 visibility:visible 是可以的,看例子。

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <style>
  .red{
	width:200px;
	height:200px;
	background:red;
  }
  .blue{
	width:200px;
	height:200px;
	background:blue;
	transition:1s;
    visibility:hidden;
  }
  .red:hover+.blue{
	visibility:visible;
  }
  </style>
 </head>
 <body>
		<div class='red'></div>
		<div class='blue'></div>
 </body>
</html>

图片描述

display 不仅不支持transition,它还会使 transition 失效。举个例子看看

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <style>
	.blue{
		width:200px;
		height:200px;
		background:blue;
	}
	.yellow{
		width:100px;
		height:100px;
		background:yellow;
		opacity:0;
		display:none;
		transition:1s
	}
	.blue:hover .yellow{
		opacity:1;
		display:block;
	}
  </style>
 </head>
 <body>
	<div class='blue'>
		<div class='yellow'></div>
	</div>
 </body>
</html>

图片描述

可以看出用了display,支持 transition 的 opacity 属性也没起作用。

这是因为display:none; 的元素,是不会渲染在页面上的,而 transition 要起作用,元素必须是已经渲染在页面上的元素,我们可以再来看个例子

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <style>
	.blue{
		width:200px;
		height:200px;
		background:blue;
	}
	.yellow{
		width:100px;
		height:100px;
		background:yellow;
		opacity:0;
		transition:1s
	}
  </style>
 </head>
 <body>
	<span>渲染到页面</span>
	<div class='blue'></div>
	
	<script>	
		var span = document.querySelector('span');
		span.addEventListener('click',function(){
			var yellowDiv = document.createElement('div');
			yellowDiv.classList.add('yellow');

			var blue = document.querySelector('.blue');
			blue.appendChild(yellowDiv);

			yellowDiv.style.opacity = '1';
		})
	</script>
 </body>
</html>

图片描述

给 span 元素绑定事件,点击它的时候,才会把黄色块div元素,渲染到DOM树上,然后改变黄色块div元素的 opacity 属性,opacity 是支持 transition 的,而在这段代码中,并没有起作用。
更详细的关于 transition 是否成功 的解读看这里
渲染树决定 transtion 能否成功

要想解决这个问题,我们可以这样做。
1、把 display 属性换成 visibility 属性

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <style>
	.blue{
		width:200px;
		height:200px;
		background:blue;
	}
	.yellow{
		width:100px;
		height:100px;
		background:yellow;
		opacity:0;
		visibility:hidden;
		transition:1s
	}
	.blue:hover .yellow{
		opacity:1;
		visibility:visible;
	}

  </style>
 </head>
 <body>
	<div class='blue'>
		<div class='yellow'></div>
	</div>
 </body>
</html>

图片描述

2、如果必须要用display属性,我们可以加上定时器来解决这个问题

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <style>
	.blue{
		width:200px;
		height:200px;
		background:blue;
	}
	.yellow{
		width:100px;
		height:100px;
		background:yellow;
		display:none;
		opacity:0;
		transition:1s;
	}
  </style>
 </head>
 <body>
	<div class='blue'>
		<div class='yellow'></div>
	</div>
	<script>	
		var blue = document.querySelector('.blue');
		blue.addEventListener('mouseenter',function(){
			var yellowDiv = document.querySelector('.yellow');
			yellowDiv.style.display = 'block';
			setTimeout(function(){
				yellowDiv.style.opacity = '1';
			},0);
		})
	</script>
 </body>
</html>

图片描述

总结

图片描述

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
Web前端工程师
手记
粉丝
62
获赞与收藏
333

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 1
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消