CSS中用 opacity、visibility、display 屬性將 元素隱藏 的 對比分析

說明

opacity 用來設置透明度css

display 定義創建佈局時元素生成的顯示框類型html

visibility 用來設置元素是否可見。segmentfault

opacity、visibility、display 這三個屬性分別取值 0、hidden、none 都能使元素在頁面上看不見,可是他們在方方面面都仍是有區別的。瀏覽器

是否佔據頁面空間

舉個例子bash

<!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>
複製代碼

最開始的樣子 app

這裏寫圖片描述

黃色塊div元素 使用 opacity:0;
佈局

這裏寫圖片描述

黃色塊div元素 使用 visibility:hidden;
ui

這裏寫圖片描述

黃色塊div元素 使用 display:none;
spa

這裏寫圖片描述

能夠看出,使用 opacity 和 visibility 屬性時,元素仍是會佔據頁面空間的,而使用 display 屬性時,元素不佔據頁面空間。ssr

對子元素的影響

若是子元素什麼都不設置的話,都會受父元素的影響,和父元素的顯示效果同樣,咱們就來舉例看看,若是子元素設置的值 和 父元素設置的值不一樣會有什麼效果。

例子 (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 屬性不必定會產生重繪。

元素提高爲合成層後,transform 和 opacity 不會觸發 repaint,若是不是合成層,則其依然會觸發 repaint。 在 Blink 和 WebKit 內核的瀏覽器中,對於應用了 transition 或者 animation 的 opacity 元素,瀏覽器會將渲染層提高爲合成層。 也可使用 translateZ(0) 或者 translate3d(0,0,0) 來人爲地強制性地建立一個合成層。

舉個例子

<!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 可否成功

要想解決這個問題,咱們能夠這樣作。

一、把 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>
複製代碼

這裏寫圖片描述

二、若是必需要用 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>
複製代碼

這裏寫圖片描述

總結

圖片描述
相關文章
相關標籤/搜索