1. 程式人生 > >CSS進階(12)—— position:absolute如此高深,我當真不懂(上)

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

  之前在探討float屬性的時候就已經提到了position:absolute的概念,絕對定位和浮動在很多方面都具有相似性,包括“塊狀化”,“包裹性”,“破壞性”等等,在理論層面上兩者是一對兄弟關係。然而在實際場景中,由於絕對定位的“破壞性”通常比float的要強,因此會有人覺得絕對定位的元素似乎跟普通的流體元素完全玩不到一塊去,事實上,除了眾所周知的需要依託最近的定位祖先節點進行定位,絕對定位元素還有很多“不脫離文件流的特性”,這在本章的“非依賴性絕對定位”中會深入探索。瞭解了絕對定位的一些基本資訊後,下面就來深入探索一下高深莫測的絕對定位吧!

1.absolute的包含塊

  在CSS世界裡,元素的大小和定位計算一直都要受包含塊的影響,如果沒有包含塊,那麼元素的資訊就會像txt文字一樣,全都顯示在一行,這顯然是不符合我們的閱讀標準的,通常情況下我們希望文字資訊能在某些符合常理的情況下自動換行,既然能換行,就必須要有包含塊的概念,有經驗的人一般都知道,普通元素的包含塊一般是他的父容器,也就是你設定某個元素的寬度為100%,那麼指的是相對於父容器的寬度進行計算後得到的寬度,而絕對定位元素的包含塊是相對於第一個position不為static的祖先元素進行計算的,由於包含塊在CSS世界的重要性,CSS規範中有明確的計算規則如下:

  (1)根元素(通常情況下就是html)被稱為初始包含塊,其尺寸等同於瀏覽器可是視窗的大小。

  (2)對於position:relative/static(預設)的元素,其包含塊由其最近的塊容器祖先盒的content-box邊界形成。

  (3)對於position:fixed的元素,其包含塊指的是初始包含塊。

  (4)對於position:absolute的元素,其包含塊由最近的position不為static的祖先元素的padding-box建立(如果祖先元素為塊元素)。如果沒有符合條件的包含塊,則包含塊是初始包含塊。

  上面四句話看著普通,實則暗藏玄機。對於純內聯元素,position:relative和static是直接無視的,因此position:relative和static的元素的包含塊不一定是其父容器,這句話有個前提條件是父容器必須為塊元素,為了證明這個觀點,我們可以來看一個例子加深一下印象。

<!-- 普通元素包含塊 -->
<div>
	<span>你好呀</span>
	<span style="max-width: 200px;">我很好,我有一個子元素
		<div style="width: 50%">我是子元素,我想看看包含塊是誰</div>
	</span>
</div>

  理論和實踐再一次統一了,上述例子中,子元素div是以最外層的div作為自己包含塊,直接無視了自己的父級span內聯標籤。

  與常規元素比,absolute元素有兩個比較明顯的特徵:

  (1)包含塊所在的元素不是父級塊元素,而是最近的position不為static的祖先元素或根元素。

  (2)邊界是padding-box而不是content-box。

  事實上除了以上兩個明顯的特徵外,absolute元素和普通元素還有一個更大的差異,就是純內聯元素也可以作為absolute元素的包含塊,只是規則要相對複雜,且不同的瀏覽器有不同的規則,因此這兒就避開不談了。好在我們在使用絕對定位的時候大部分是用他來進行佈局,跟展示圖文為主的內聯元素本身就玩不到一塊去,因此我們就可以理直氣壯的不去探索這個特性了。

  利用絕對定位元素計算的容器是第一個position不為static的祖先元素,我們可以衍生出一個非常好用的小tips,就是對於絕對定位元素height:100%和height:inherit是有區別的,前者可能基於祖先元素定位,後者單純的繼承了父元素的高度,在某些場景下非常好用。

  現在我們已經“完全”瞭解了絕對定位元素的“包含塊”是如何產生的了,因此我們需要通過一個小測試來驗證其實用性。

<!-- 滑鼠懸浮展示文字效果 -->
 <div class="icon"></div>
 <style>
 	.icon{
 		position: relative;
 		width: 16px;
 		height: 16px;
 		background: url('../pic_title_left.png') center;
 	}
 	/*.icon:hover::after{
 		content: '圖示';
 		position: absolute;
 		top: 100%;
 		background: rgba(0,0,0,0.8);
 		color: white;
 	}*/
 	/*為了展示更清除不使用滑鼠移入事件*/
 	.icon::after{
 		content: '圖示';
 		position: absolute;
 		top: 100%;
 		background: rgba(0,0,0,0.8);
 		color: white;
 	}
 </style>

  

  此例中,我們希望實現一個滑鼠移入圖示,顯示提示資訊的效果,可以看到絕對定位元素的寬度被限制在父容器的16px,此時文字的主動換行變成了一種不怎麼好看的“一柱擎天”效果,這就是絕對定位的元素的“包裹性”,因此絕對定位元素的“包裹性”依賴於“包含塊”。要修復問題其實很簡單,只要改變預設的寬度型別就可以了,新增white-space:nowrap,讓寬度表現從“包裹性”變成“最大可用寬度”,就可以實現想要的效果了。

  下面我們再來看一下,position:absolute為什麼要以padding-box作為邊界,這其實和overflow隱藏也是padding-box作為邊界類似,是由實際開發場景決定的。舉個例子,如我們在開發某個文字欄目的時候,需要兩側有一定的留白,這個留白我們通常會用padding撐開,而不是margin,因為margin是全透明的,在背景顏色設定上會遇到一些麻煩,當然我們也不會考慮用border撐開,因為我們打心底認為border是用來做邊框的。這時候我們需要在右上角固定一個圖示,如“部落格專家”的圖示,你希望這個圖示放在什麼位置?或者說,右上角的概念是什麼?CSS幫我們做了取捨,CSS認為,應該放到padding-box的外邊緣,而不是content-box,事實上這樣看起來確實比較美觀,如下所示。

 <!-- 圖示固定在右上角的效果 -->
 <div class="content">
 	我這裡有很多內容,但我需要有一個內邊距,我還要在右上角放個圖示
 	我這裡有很多內容,但我需要有一個內邊距,我還要在右上角放個圖示
 	我這裡有很多內容,但我需要有一個內邊距,我還要在右上角放個圖示
 	我這裡有很多內容,但我需要有一個內邊距,我還要在右上角放個圖示
 	我這裡有很多內容,但我需要有一個內邊距,我還要在右上角放個圖示
 	我這裡有很多內容,但我需要有一個內邊距,我還要在右上角放個圖示
 	我這裡有很多內容,但我需要有一個內邊距,我還要在右上角放個圖示
 	我這裡有很多內容,但我需要有一個內邊距,我還要在右上角放個圖示
 	我這裡有很多內容,但我需要有一個內邊距,我還要在右上角放個圖示
 </div>
 <style>
 	.content{
 		position: relative;
 		width: 400px;
 		padding: 20px;
 		border:2px solid #ccc;
 		border-radius: 4px;
 	}
 	.content::before{
 		content: '假設我是個圖示';
 		position: absolute;
 		right: 0;
 		top: 0;
 		line-height: 20px;
 		width: 70px;
 		height: 40px;
 		background: yellow;
 	}
 </style>

  如果你需要右上角的定義是content,那麼CSS也給你留有一絲餘地,注意不要用right:padding-right,top:padding-top,那樣就太蠢了,而且增加了右上角和padding的耦合性,你完全可以使用border留白來實現這個效果,這個時候就不要請padding幫忙了。

2.具有相對特性的無依賴absolute定位

  很多人對於absolute的印象是“完全破壞文件流”,這可能是CSS歷史上最大的冤假錯案了,這甚至比clear清浮動還冤,畢竟clear清浮動好歹從表現上“清除了浮動”。而absolute則被認為預設定位在包含塊的左上角。我們可以通過一個簡單的例子來驗證一下,一個絕對定位元素在沒有left/r/t/b的情況下會在定位到哪裡?

 <div style="position: relative;">
 	我是包含塊
 	<div style="position: absolute;">我是絕對定位元素</div>
 </div>

   很多人會覺得,絕對定位元素會和包含塊內的文字重合在一起顯示,事實上測試結果如下圖所示

  絕對定位元素並沒有和包含塊的文字發生重合,而是中規中矩的呆在後面,當然絕對定位的“破壞性”依舊存在,可以看到父容器div的高度不包含絕對定位元素的高度。作者把這種沒有設定left/right/top/bottom屬性值的絕對定位稱為“無依賴絕對定位”,這種絕對定位屬性擁有兩個顯著特性:1.破壞性,2.相對性。無依賴絕對定位本質上可以看作是relative相對定位,只是不佔據CSS的尺寸流而已,也就是他在保持破壞性的基礎上,保留了一定的“相對性”。聽起來有一種,先按照相對定位進行計算位置,然後把自己抽離文件流的定位方式。這種不佔位置的相對定位特性在實際開發的時候實則非常有用,為了加深大家對這個概念的印象,我們來舉幾個例子說明。

  1)我們需要實現一張圖的左上角有一個小圖示。這時候我們僅需用一個樣式就能搞定,而不需要多餘的left,top申明。

<!-- 圖片定位到左上角 -->
<img src="top1.png" style="position:absolute"><img src="1.jpg">

  2)我們需要實現一些帶上標的文字,vertical-align中也有上標下標屬性,但由於內聯元素會佔據位置,會影響元素的居中顯示,通常情況下我們還是會藉助到絕對定位不佔位置的特性去實現下圖的效果。


 <!-- 文字定位到右上角 -->
 <div class="container">
 	<div class="li">
 		<div class="word">普通導航</div>
 	</div>
 	<div class="li">
 		<div class="word">熱門導航
 				<span class="icon">hot</span>
 		</div>
 	</div>
 	<div class="li">
 		<div class="word">新導航
 				<span class="icon">new</span>
 		</div>
 	</div>
 </div>
 <style>
  .container{
  	margin: auto;
  	background: #ccc;
  }
  .li{
  	display: inline-block;
  	width: 200px;
  	text-align: center;
  }
  .word{
  	padding: 20px;
  }
 	.icon{
 		position: absolute;
 		color: red;
 		margin: -6px 0 0 4px;
 		font-size: 12px;
 	}
 </style>

3)最後一個例子是一個比較常用的登陸註冊提示功能,如下圖所示。

  

<!-- 登入註冊提示 -->
 <div class="container">
 	<div class="line">
 		<label>使用者名稱</label>
 		<div>
 			<input type="text" placeholder="請輸入使用者名稱">
 			<i>*使用者名稱不正常</i>
 		</div>
 	</div>
 	<div class="line">
 		<label>密碼</label>
 		<div>
 			<input type="text" placeholder="請輸入密碼">
 			<i>*密碼不支援</i>
 		</div>
 	</div>
 	<div class="line">
 		<label>手機號</label>
 		<div>
 			<input type="text" placeholder="請輸入手機號">
 		</div>
 	</div>
 </div>
 <style type="text/css">
.container{
	width: 400px;
	margin: auto;
}
.line{
	margin:20px 0;
}
.line label{
  font-size: 18px;
	line-height: 40px;
	float: left;
}
.line div{
	margin-left: 4em;
}
.line input{
	width: 320px;
	font-size: 18px;
	padding: 9px 5px;
  border: 1px solid #d0d6d9;
  vertical-align: top;
}
.line i{
	position: absolute;
	line-height: 40px;
	margin-left: 20px;
	color:red;
}
</style>

  除了上述幾種效果之外,無依賴絕對定位還可以幫助我們實現下拉框,模擬佔位符等,在這裡就不過多贅述了,舉了三個例子也是為了幫助大家理解無依賴絕對定位的使用場景。

  最後我們來重點關注一下無依賴絕對定位的“塊狀化”,通常意義上,塊狀化指的是display的計算值是塊狀的,也就是說聲明瞭position:absolute,相當於同時申明瞭display:block,但該元素的位置卻和元素本身的屬性相關。聽起來有點繞,我們來看一個例子對比一下就明白了。

<!-- 深入理解無依賴定位 -->
 <div style="position: relative;background: yellow">
 	我是包含塊
 	<span style="position: absolute;">我是絕對定位元素</span>
 </div>

  <div style="position: relative;background: yellow">
 	我是包含塊
 	<div style="position: absolute;">我是絕對定位元素</div>
 </div>

  上面這個例子中,絕對定位元素在未被宣告position:absolute之前,一個是塊級元素,一個是內聯元素,因此一個是換行顯示,另一個是同行顯示,在聲明瞭absolute後,雖然計算值都變成了block,但其位置仍然跟之前定位的相同。

  本章我們已經深入瞭解了絕對定位的包含塊以及“無依賴絕對定位”的特性,下一章我們來聊聊absolute的流體特性以及absolute和其他CSS相互之間的愛恨情仇。