CSS進階(13)—— position:absolute如此高深,我當真不懂(中)

閒人王昱珩發表於2018-12-10

  在上文中,我們探討了絕對定位的包含塊以及“無依賴絕對定位”的特性,本章我們來聊聊absolute的流體特性以及那些和absolute關係甚好的CSS屬性。

1.absolute的流體特性

  在前面一文中,我們測試了很多“無依賴絕對定位”的特殊表現,事實上在平時開發的時候我們使用absolute都用的都是他的“絕對定位”特性,這也是absolute被設計出來的本職工作。為了做好自己的本職工作,absolute還需要left,top,right,bottom四個屬性的配合,通常,我們會根據閱讀順序(從左到右,從上到下)的需要,設定absolute元素的left和top值,來達到元素定位的效果,那麼,如果僅設定一個方向上的值,會發生什麼呢?這裡我們不深入探討這種情形,你只需要知道元素在被設定的方向上保持“絕對定位”的特性,而在另一個(水平或垂直)方向上保持相對定位特性即可。

  本節要深入探討的是absolute的流體特性。說到流體特性,我們應該能很快想到<div>之類的普通塊級元素,實際上,絕對定位元素也具有類似的流體特性,而且在某些情況下比普通塊級元素更強大!當然,absolute要實現自身的流體特性是有條件的,給元素直接設定style="position:absolute;margin:auto;"外邊距的auto屬性是不會有任何計算值的。那麼,absolute元素才能擁有流體特性呢?這個條件就是“對立方向同時發生定位”的時候。

  left,top,right,bottom是具有定位元素的專用CSS(注意不只是絕對定位),其中left和right屬於水平對立定位方向,而top和bottom屬於垂直對立定位方向。當一個絕對定位元素,其對立定位方向屬性同時具有值得時候,那麼該元素在該對立方向上具有流體特性,當然如果你樂意的話,絕對定位元素可以同時在水平和垂直方向上都具有流體特性。流體特性最顯著的特點就是自動鋪滿流體方向上的空間,就像物理世界的水會鋪滿燒杯一樣。下面我們來測試一下該特性的具體表現。

 <!-- 絕對定位的流體特性 -->
<div style="position:relative;height: 100px;background: yellow;margin: 20px;">
	<div style="position: absolute;background: #f34413;left: 0;right: 0">我是水平流</div>
</div>
<div style="position:relative;height: 100px;background: yellow;margin: 20px;">
	<div style="position: absolute;background: #f34413;top: 0;bottom: 0">我是垂直流</div>
</div>
<div style="position:relative;height: 100px;background: yellow;margin: 20px;">
	<div style="position: absolute;background: #f34413;left: 10px;right:10px;top: 10px;bottom: 10px">
	我是水平垂直流</div>
</div>

  如果只有left屬性沒有right屬性,absolute則表現為“包裹性”。在垂直方向上的表現同理。

<div style="position:relative;height: 100px;background: yellow;margin: 20px;">
	<div style="position: absolute;background: #f34413;left: 0;">包裹性</div>
</div>

 

  下面我們要實現一個元素完全覆蓋瀏覽器可視視窗的效果,有很多種方法可以實現這個效果,下面我們只關注用absolute如何實現這種效果。

<style>
.box1{
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
}
</style>

 

<style>
.box1{
    position: absolute;
    left:0;
    top:0;
    width:100%;
    height:100%;
}
</style>

  上面這兩種方法都可以實現元素鋪滿整個螢幕的效果(在包含塊是HTML的情況下),但是他們的實現原理卻完全不同,後者也就是設定了寬高的那個元素,實際上已經完全失去了流動性,而且當前元素的寬高已經被準確計算了,此時你還想要新增內邊距或外邊距便會造成“寬高溢位”的表現,而用第一種方法實現則完全不會出現這種情況。

2.利用absolute實現水平垂直居中

  我們可以利用absolute的流體特性實現一種常用的佈局——水平垂直居中。我們都知道,塊級元素本身具有流體特性,在margin一章中我們也詳細介紹了margin:auto的自適應計算屬性。當元素具有流體特性,如div在水平方向上具有流體特性,此時設定margin:auto,該元素的外邊距就會在水平方向上自動等分成兩份,使得元素本身在父容器中顯示為水平居中效果。因此,margin的auto屬性用在具有垂直水平都具有流體特性的absolute元素上時,就能讓元素實現自適應居中!這種居中方式是目前為止最好的水平垂直居中解決方案,來看下面的演示。

 <!-- absolute流體特性 -->
 <div class="father">
 	<div class="son"></div>
 </div>
 <style type="text/css">
 	.father{
 		width: 400px;
 		height: 400px;
 		background: yellow;
 		position: relative;
 	}
 	.son{
 		width: 200px;
 		height: 100px;
 		background: green;
 		position: absolute;
 		top: 0;
 		right: 0;
 		bottom: 0;
 		left: 0;
 		margin: auto;
 	}
 </style>

 

  

  事實上absolute還有一種做法也可以實現元素的水平垂直居中,這種做法需要藉助transform配合,我們先來看一下演示。

<!-- 利用transfor實現 -->
 <div class="father">
 	<div class="son"></div>
 </div>
 <style type="text/css">
 	.father{
 		width: 400px;
 		height: 400px;
 		background: yellow;
 		position: relative;
 	}
 	.son{
 		width: 200px;
 		height: 100px;
 		background: green;
 		position: absolute;
 		top: 50%;
 		left: 50%;
 		transform: translate(-50%,-50%);
 	}
 </style>

  由於最終展示的結果是一樣的,這裡就不放圖片了,看起來下面的這種做法也非常優秀,但其實還是有一些問題的。之前我在探討元素的垂直居中的時候就發現了這種方法的一些“缺點”。首先,他沒有利用元素自適應佈局的特點,也就是元素完全脫離了文件流,這可能對CSS強迫症愛好者來說有些不爽。當然這只是一個小缺點,此類佈局最大的問題就是要考慮absolute的包裹性!我剛才已經提到了absolute元素如果只有left屬性沒有right屬性,absolute則表現為“包裹性”。在垂直方向上的表現同理。因此在本例中,該元素表現出了包裹性,包裹性包括包裹和自適應兩大特性,這個我也說了好多遍了,由於設定了left:50%,因此son元素的自適應最大寬度不得超過50%,也就是明明還有可適應的空間,他卻自動換行了。我們可以在son中填充一些文字看一下效果。

  要解決這個問題很簡單,只要給absolute元素加上white-space:norwap強制文字不換行即可,但這樣也會有問題,就是文字內容會超出父容器,因此個人建議棄用這種垂直居中的佈局方式。

3.absolute與text-align

  眾所周知,text-align從字面上理解是指文字的對齊方式,因此控制的是內聯元素的表現,而absolute具有塊狀化元素的特性,因此這兩個屬性可以說是八杆子打不著的關係。然而在下面這段程式碼中,text-align屬性似乎對absolute元素產生了影響。

 <!-- absolute與text-align -->
 <div style="text-align: center;">
 	<span style="position: absolute;">hello</span>
 </div>

  

    上圖中,absolute元素似乎受到text-align的影響處於容器中偏右的位置,那麼text-align真的可以影響塊元素嗎?答案是否定的。在本例中,text-align影響的依舊是內聯元素,只是這個內聯元素是你看不到“幽靈空白節點”。由於span標籤原來是個內聯元素,因此在該元素前面生成了一個幽靈空白節點,這個節點預設是個內聯元素,受到了text-align:center的感化,跑到了div的中間,雖然不佔位置,但佔據了一個看不見的空間,而這個看不見的空間對後面的“無依賴絕對定位”元素產生了影響,這個absolute元素就乖乖的跟在後邊了。因此本例中,absolute元素並不是直接和text-align發生關係!

4.absolute和overflow

  overflow對absolute元素的裁切規則的官方描述是:絕對定位元素不總是被父級overflow屬性裁剪,尤其當overflow在絕對定位元素及其包含塊之間的時候。

  翻譯一下上面這句話:如果overflow不是定位元素,同時絕對定位元素和overflow容器之間也沒有定位元素,則overflow無法對absolute元素進行裁切。事實上你根本記不住這句話,所以你得常用,慢慢記到腦子裡。下面我會用一些例項來強化一下你的印象,從0% 到 1%吧,剩下99%靠你自己了,我寫部落格也是為了加深印象,這個系列的內容很多都只要留個潛意識即可,以後遇到問題知道去哪裡查閱就ok了。

  下面四個例子可以幫助你快速記憶absolute什麼時候會被overflow裁切。

 <!-- absolute與overflow -->
 <!-- html作為定位元素 -->
<div class="box">
	<img src="./小和尚.jpg" /> 	
</div>
<!-- overflow父元素是定位元素,跟html做定位元素同理 -->
<div style="position: relative;">
	<div class="box">
		<img src="./小和尚.jpg" /> 	
	</div>
</div>
<!-- overflow元素本身是定位元素 -->
<div class="box" style="position: relative;">
	<img src="./小和尚.jpg" /> 	
</div>
<!-- overflow元素與絕對定位元素之間有定位元素 -->
<div class="box" style="position: relative;">
	<div style="position: relative;">
		<img src="./小和尚.jpg" />
	</div> 	
</div>
 <style>
 	.box{
 		width: 80px;
 		height: 120px;
 		overflow: hidden;
 		background: yellow;
 		margin: 10px;
 	}
 	img{
 		position: absolute;
 		width: 100px;
 		height: 100px;
 	}
 </style>

  

  除了hidden"裁切"屬性,overflow還有auto和scroll屬性,這兩個屬性在遇到絕對定位的時候選擇直接無視,即使絕對定位元素寬高大於overflow元素,也不會出現滾動條。

 <!-- absolute與滾動條 -->
 <div class="box">
 	<img style="position: absolute;" src="./小和尚.jpg" />
 </div>
 <style>
 	.box{
 		width: 300px;
 		height: 200px;
 		overflow: auto;
 		background: yellow;
 	}
 </style>

  雖然絕對定位元素不能影響元素出現滾動條,但普通元素可以,在box元素中填充足夠內容後,我們來看下滾動條和absolute元素的真實關係。

 <!-- absolute與滾動條 -->
 <div class="box">
 	<img style="position: absolute;opacity: 0.2" src="./小和尚.jpg" />
 	<p>文字內容文字內容文字內容文字內容文字內容文字內容文字內容</p>
 	<p>文字內容文字內容文字內容文字內容文字內容文字內容文字內容</p>
 	<p>文字內容文字內容文字內容文字內容文字內容文字內容文字內容</p>
 	<p>文字內容文字內容文字內容文字內容文字內容文字內容文字內容</p>
 	<p>文字內容文字內容文字內容文字內容文字內容文字內容文字內容</p>
 </div>
 <style>
 	.box{
 		width: 300px;
 		height: 200px;
 		overflow: auto;
 		background: yellow;
 	}
 </style>

  可以看到,滾動條滾動的過程中,absolute元素紋絲不動,利用這個特點我們可以用來實現元素固定到頂部的效果,且該元素不會隨著滾動條滾動。本人測試了一下該原理實現的效果並不是很好,且鑑於小白維護程式碼的時候會莫名其妙給標籤加個relative的屬性,不便於不明白此“奇怪特性”的人維護CSS,因此只要知道有這個特性即可,不需要太過深入。

5.absolute與clip:初次見面,請多指教

  CSS世界中有些屬性必須和其他屬性一起使用才有效,如之前講過的“文字超出部分省略號顯示”效果。clip裁切屬性想要起作用,元素必須是絕對定位(absolute)或固定定位(fixed)。clip語法如下:

  clip:rect(top right bottom left)  或 rect(top,right,bottom,left) 

   該屬性有兩個注意點,搭配起來看會非常蛋疼:1.top和bottom的值都相對於頁面垂直流的top,也就是說,是在元素的top裁切到bottom,left和right同理,是相對於頁面水平流的left。2.該屬性不支援百分比。

  作者非常喜歡稱overflow:hidden為"裁切"屬性,我個人更傾向於“隱藏”,因為hidden並不是真的裁切了元素,在overflow一章我們詳細探討過如果顯示overflow:hidden部分的內容。本章要探討的clip屬性更具備“裁切”的特性,由於其必須搭配absolute/fixed才能使用,因此很多人甚至都沒有用過這個屬性,事實上這個屬性我們不僅需要了解,在某些方面他還非常有用。

1)fixed固定定位裁切

  對於普通元素或者絕對定位元素,想要對其裁剪,我們可以使用relative搭配overflow:hidden的方式,然而fixed定位的包含塊是根元素,這時候我們想要用overflow:hidden的方式必須要給根元素申明,這樣用起來就比較蛋疼了,因為通常情況下我們希望根元素的寬高能自適應。此時就需要用到clip屬性了。

<!-- clip裁切fixed元素 -->
<div class="box">
	<img src="./小和尚.jpg">
</div>
<style>
	.box{
		position: fixed;
		clip: rect(30px 200px 200px 20px)
	}
</style>

  由於clip裁切的計算是相對於頁面的“左上角”的,且不支援百分比計算,因此這個裁切屬性用起來不是非常方便,只能在某些特定寬高確定的元素裡有一些作用,瞭解一下即可。

2)最佳可訪問隱藏屬性

  所謂“可訪問性隱藏”指的是雖然內容肉眼看不見,但是其輔助功能卻能夠識別,舉個例子,我們需要用到一個logo圖示,為了更好的SEO以及無障礙識別,我們一般會使用<h1>標籤寫上網站的名稱,程式碼如下

<a href="/" class="logo">
 <h1>CSS世界</h1>
</a>

  此時我們需要隱藏CSS世界的文字,通常有以下幾種做法。

  1.用display:none或者visibility:hidden隱藏,螢幕閱讀裝置會直接忽略文字。

  2.text-indene:-9999,由於文字縮排過大,螢幕閱讀裝置也不會讀取文字。

  3.color:transparent,文字框依舊在html中,可被使用者選擇到,需要取消瀏覽器的預設事件,操作麻煩。

  4.clip裁剪隱藏,既滿足視覺上的隱藏,螢幕閱讀裝置也支援的較好。

  鑑於clip裁切是“最佳可訪問隱藏”,我推薦在common.css中放入如下class類表示隱藏。

.clip{
   position:absolute;
   clip:rect(0,0,0,0)
}

 該屬性隨取隨用,且無依賴絕對定位的相容性非常好,不會影響正常佈局。利用clip裁切不會影響元素本身的特性,我們可以利用他完成表單元素的修改,並保留表單元素的預設操作,如focus,submit等操作,具體這裡不過多展開。

 

  本章主要介紹了絕對定位的流體特性以及和絕對定位相關的CSS屬性,然而跟絕對定位最親密的relative屬性還沒有介紹,鑑於relative和fixed的特殊性,這兩個絕對定位好基友我們放到下一章介紹,感興趣的點個關注吧~

相關文章