CSS絕對定位absolute詳解

轉:https://www.jianshu.com/p/a3da5e27d22bjavascript

 
 

以前介紹過CSS浮動float詳解,本篇介紹的絕對定位absolute和浮動float有部分類似性。若是能理解浮動float,對理解絕對定位absolute會大有幫助。前端

先說absolute和float的類似處:包裹性高度欺騙java

包裹性

所謂一圖勝千言(惟一的區別是:下圖的div增長了absolute)瀏覽器

 
 
 
<div style="border:4px solid blue;">
  <img src="img/25/1.jpg" />
</div>
<div style="border:4px solid red; position: absolute;">
  <img src="img/25/2.jpg" />
</div>

 

  

一旦給元素加上absolute或float就至關於給元素加上了display:block;。什麼意思呢?好比內聯元素span默認寬度是自適應的,你給其加上width是不起做用的。要想width定寬,你須要將span設成display:block。但若是你給span加上absolute或float,那span的display屬性自動就變成block,就能夠指定width了。所以若是看到CSS裏absolute/float和display:block同時出現,那display:block就是多餘的CSS代碼。ide

高度欺騙

上例中給圖片外層的div加上absolute,所以高度欺騙未能很好的體現出來,將absolute移到內部圖片上,效果就出來了:佈局

 
 
<div style="border:4px solid blue;">
  <img src="img/25/1.jpg" />
</div>
<div style="border:4px solid red;">
  <img style="position: absolute;" src="img/25/2.jpg" />
</div>

 

若是你看過CSS浮動float詳解會發現效果是同樣的。但其背後的原理實際上是有區別的,並不徹底相同。加點文字就看出來了:
動畫

 
 

 

<div style="border:4px solid blue;">
  <img src="img/25/1.jpg" />
</div>
<div style="border:4px solid red;">
  <img style="position: absolute;" src="img/25/2.jpg" />
  我是一個絕對定位的absolute元素
</div>

 

從圖中明顯看出文字被圖片遮蓋了,這點和float不一樣。float是欺騙父元素,讓其父元素誤覺得其高度塌陷了,但float元素自己仍處於文檔流中,文字會環繞着float元素,不會被遮蔽。spa

但absolute其實已經不能算是欺騙父元素了,而是出現了層級關係。若是處於正常的文檔流中的父元素算是凡人的話,那absolute已經得道成仙,用如今的話說已經不在一個次元上。從父元素的視點看,設成absolute的圖片已經徹底消失不見了,所以從最左邊開始顯示文字。而absolute的層級高,因此圖片遮蓋了文字。插件

記得我剛開始接觸CSS尚處於戰鬥力爲5的渣渣時,知道了absolute能夠出現層級的概念,就誤覺得已經完全懂了,如今想一想真是圖樣圖森破(固然這不是件壞事,每當你以爲之前的本身渣像塊豆腐渣時,就表明你進步了。反過來總說想當年本身如何如何,那說明你還在吃老本)。3d

有了上面的基礎後,你還須要瞭解absolute如下特性

  • 如何肯定定位點
  • 和relative相愛相殺
  • 和z-index的關係
  • 減小重繪和迴流的開銷

如何肯定定位點

一旦absolute分層後,第一個出現的問題就是讓瀏覽器在何處顯示該元素。普通文檔流裏的元素,瀏覽器能夠根據其父子兄弟元素的大小和位置,計算出該元素的位置。但分層後怎麼辦?基本思路以下:

第一種狀況:用戶只給元素指定了absolute,未指定left/top/right/bottom。此時absolute元素的左上角定位點位置就是該元素正常文檔流裏的位置。如上面圖例中,圖片熊貓是父元素的第一個孩子,所以左上角定位點就是父元素的content的左上角。

若是將圖片熊貓和下面的文字順序改一下,讓其成爲父元素的第二個孩子,一圖勝千言:

 
 
<div style="border:4px solid red;">
  我是一個絕對定位的absolute元素
  <img style="position: absolute;" src="img/25/2.jpg" />
</div>

 

結論重複一遍:未指定left/top/right/bottom的absolute元素,其在所處層級中的定位點就是正常文檔流中該元素的定位點。

第二種狀況:用戶給absolute元素指定了left/right,top/bottom

先簡單點,讓absolute元素沒有position:static之外的父元素。此時absolute所處的層是鋪滿全屏的,即鋪滿body。會根據用戶指定位置的在body上進行定位。

只指定left時,元素的左上角定位點的left值會變成用戶指定值。但top值仍舊是該元素在正常文檔流中的top值:

 
 
<div style="border:4px solid red;">
  我是一個絕對定位的absolute元素
  <img style="position: absolute;left:50px;" src="img/25/2.jpg" />
</div>

 

只指定right時,元素的右上角定位點的right值會變成用戶指定值。但top值仍舊是該元素在正常文檔流中的top值:

 
 
<div style="border:4px solid red;">
  我是一個絕對定位的absolute元素
  <img style="position: absolute;right:50px;" src="img/25/2.jpg" />
</div>

 

只指定top時,元素的左上角定位點的top值會變成用戶指定值。但left值仍舊是該元素在正常文檔流中的left值:

 
 
<div style="border:4px solid red;">
  我是一個絕對定位的absolute元素
  <img style="position: absolute;top:50px;" src="img/25/2.jpg" />
</div>

 

只指定bottom時,元素的左下角定位點的bottom值會變成用戶指定值。但left值仍舊是該元素在正常文檔流中的left值:

 
 
<div style="border:4px solid red;">
  我是一個絕對定位的absolute元素
  <img style="position: absolute;bottom:50px;" src="img/25/2.jpg" />
</div>

 

經過對left/top/right/bottom的組合設置,因爲沒有position:static之外的父元素,此時absolute元素能夠去任意它想去的地方,天空纔是它的極限。

和relative相愛相殺

一般咱們對relative的認識是(好吧,我認可,這是我戰5渣渣時的認識。若是你是弗利薩,能夠鄙視這句話):relative主要用於限制absolute

上面已經說了,若是absolute元素沒有position:static之外的父元素,那將相對body定位,天空纔是它的極限。而一旦父元素被設爲relative,那absolute子元素將相對於其父元素定位,就好像一隻腳上被綁了繩子的鳥。

好比你要實現下圖iOS裏APP右上角的紅色圈圈

 
 

一般的作法是將APP圖片所處的div設成relative,而後紅色圈圈設成absolute,再設top/right便可。這樣不管用戶怎麼改變APP圖片的位置,紅色圈圈永遠固定在右上角,例如:

 
 
.tipIcon {
  background-color: #f00;
  color: #fff;
  border-radius:50%;
  text-align: center;
  position: absolute;
  width: 20px;
  height: 20px;
  right:-10px;  //負值爲自身體積的一半
  top:-10px;
}

<div style="display: inline-block;position:relative;">
  <img src="img/25/2.jpg" />
  <span class="tipIcon">6</span>
</div>

 

這樣作效果是OK的,兼容性也OK。但CSS的世界裏要實現一個效果能夠有不少種方式,具體選用哪一個方案是見仁見智的。我比較看重的標準:一個是簡潔,另外一個是儘可能讓每一個屬性幹其本職工做。

用這兩個標準看待上述實現方法,應該是有改進的空間的。首先外層div多了relative未能簡潔到極致。其次relative的本職工做是讓元素在相對其正常文檔流位置進行偏移,但父層div並不須要任何位置偏移,之因此設成relative惟一的目的是限制absolute子元素的定位點。所以在我看來這並無讓relative幹其本職工做。比如小姐的本職工做是服務業,順便陪客戶聊聊天,但純聊天聊完一個鐘,恐怕會被投訴。

那怎麼改進呢?答案在上面探討absolute定位點時已經說了:未指定left/top/right/bottom的absolute元素,其在所處層級中的定位點就是正常文檔流中該元素的定位點。所以改進以下:

.tipIcon2 {
  background-color: #f00;
  color: #fff;
  border-radius:50%;
  text-align: center;
  position: absolute;
  width: 20px;
  height: 20px;
  margin:-10px 0 0 -10px;   //不須要top和right了,改用margin來進行偏移
}

<div style="display: inline-block;">  //父元素不須要relative了
  <img src="img/25/2.jpg" /><!--
 --><span class="tipIcon2">6</span> 
</div>
//img和soan間的HTML註釋的目的是消除換行符,你也能夠將span緊跟在img後面寫到一行裏

 

更深刻一點看,多一個屬性意味着多一層維護。若是用父relative + 子absolute來實現定位,萬一未來頁面佈局要調整,父元素的尺寸須要變換呢?

 
 
<div style="display: inline-block; position:relative;width: 200px;">
  <img src="img/25/2.jpg" />
  <span class="tipIcon">6</span>
</div>

 

上面僅僅因爲父元素的width作了些改變,致使右上角absolute圖標錯位了。因爲absolute和relative耦合在了一塊兒,父元素有點風吹草動(如尺寸變化,或乾脆須要去掉relative),子元素須要從新尋找定位點。苦逼的前端仔拿着微薄的工資在那裏加班加點,那是大大地不划算。但若是用上例中absolute自身的定位特性,不管父元素怎麼折騰,紅色的圈圈都緊緊黏在圖片的右上角。

這麼說來relative和absolute是否應該完全斷絕關係呢?不是這樣的,這段的標題是「和relative相愛相殺」,剛纔說的想殺部分,如今說下什麼相愛部分。

用absolute常見的一個案例是透明層覆蓋元素。要實現對全屏加一層濾鏡怎麼辦?很容易:

 
 
.cover {
    position: absolute;
    left: 0;right: 0;top: 0;bottom: 0;
    background-color: #fff;
    opacity: .5;filter: alpha(opacity=50);
}

<div style="display: inline-block;">
  <img src="img/25/2.jpg" /><!--
  --><span class="tipIcon2">6</span>
</div>
如今是全屏濾鏡時間
<span class="cover"></span>

 

CSS裏有個細節值得關注:用absolute的left: 0;right: 0;top: 0;bottom: 0;來實現全屏拉伸,對於absolute元素來講,若是同時設置left和right會水平拉伸,同時設置top和bottom會垂直拉伸。那爲什麼不設width/height爲100%呢?代碼都貼給你了,能夠本身試試。算了告訴你答案吧,前面說了,不設top/right/top/bottom的話absolute會從正常文檔流應處的位置開始定位,所以作不到全屏。除非你設置width/height爲100%後,同時再設left: 0; top: 0;。這樣就顯得很囉嗦。

那我不想全屏濾鏡,只但願給圖片部分設置濾鏡呢?用js計算圖片的大小尺寸和定位點後,設置absolute濾鏡的尺寸和定位點?太麻煩了。用relative吧

 
 
//CSS部分不變
<div style="display: inline-block;position: relative;">
  <span class="cover"></span>
  <img src="img/25/2.jpg" /><!--
  --><span class="tipIcon2">6</span>
</div>
 如今是圖片濾鏡時間 

結論:

1.相對定位時,沒必要拘泥於relative+absolute,試試去掉relative,充分利用absolute自身定位的特性,將relative和absolute解耦。耦合度越低維護起來越容易,前端仔騰出時間陪女友吃飯纔是正道。

2.拉伸平鋪時,用relative能夠有效限制子absolute元素的拉伸平鋪範圍(注意是拉伸,不是縮小。要縮小請再加上width/height:100%;)

和z-index的關係

z-index被太多的濫用了。幾乎成了個定勢思惟:只要設了absolute就須要同步設置z-index。其實不是這樣的。上面全部例子都沒有用到z-index,一樣正常分層正常覆蓋。

如下狀況根本不須要設z-index:

  • 讓absolute元素覆蓋正常文檔流內元素(不用設z-index,天然覆蓋)
  • 讓後一個absolute元素覆蓋前一個absolute元素(不用設z-index,只要在HTML端正確設置元素順序便可)

那何時須要設置z-index呢?當absolute元素覆蓋另外一個absolute元素,且HTML端不方便調整DOM的前後順序時,須要設置z-index: 1。很是少見的狀況下多個absolute交錯覆蓋,或者須要顯示最高層次的模態對話框時,能夠設置z-index > 1。

比較好的是京東,查看首頁源碼,設置z-index的地方也只設了1,2,3。少數地方設了11,12,13。我更傾向於理解爲是一種內部潛規則,代表更高層級的一種須要。

要舉反例能夠看渣浪:

 
 

查看源碼,果真發現了z-index:99,當你設成99後,如今我須要一個更高的層級怎麼辦?重構頁面代碼,將99等重構成1,2,3?能夠想見,前端仔瞄了一眼工資單後,放棄重構,果斷將該元素的z-index設成999。恩,沒什麼很差的,淡定~

若是你的頁面不比京東更復雜,那z-index一般設成1,2,3足夠了。

減小重繪和迴流的開銷

例如將元素隱藏,你或許會用display:none。

(這裏插一句題外話,用display:none隱藏容易顯示難,若是你用的是JQuery等插件,你或許會疑惑,直接用show/hide API不就好了,難在哪裏?其中一個難點就是保存隱藏前元素的display屬性值。例如A隱藏前display:block,B隱藏前display:inline,A和B都改爲none隱藏後,要顯示出來時,你必須事先保存元素的display屬性值,不然作不到顯示後display仍舊是原先的值。而這些工做JQuery插件都替你作好了,才讓你產生了隱藏顯示很容易的錯覺。)

其實我更推薦的是absolute控制隱藏和顯示。方法固然至關簡單,如absolute+ top:-9999em,或absolute + visibility:hidden。

優勢是absolute因爲層級的關係,隱藏和顯示只會重繪,但不會迴流(其實我對absolute不會致使迴流這一觀點是持懷疑態度的,說不會迴流顯得過於武斷,應該是absolute的迴流開銷小於正常DOM流中迴流的開銷。但我戰鬥力不夠,還沒有找到靠譜合理的檢測迴流的方法)。而用display:none會致使render tree重繪和迴流。

另外,考慮到重繪和迴流的開銷,能夠將動畫效果放到absolute元素中,避免瀏覽器將render tree迴流。

總結

在這個快餐年代,能堅持10分鐘看到這裏的已經很是不容易了。(我假設你沒拖動滾動條快進_

做者:張歆琳 連接:https://www.jianshu.com/p/a3da5e27d22b 來源:簡書
相關文章
相關標籤/搜索