本文由 Rhyme、Captain 發表在 ScalaCool 團隊博客。css
本文旨在讓你更深刻地瞭解position
,併爲你提供一套使用position
的範式,爲你使用position
提供一點建議和參考。html
在此以前先讓咱們來看看 learncss 中文文檔中對position
的定義web
值 | 描述 |
---|---|
absolute | 生成絕對定位的元素,相對於 static 定位之外的第一個父元素進行定位。元素的位置經過 "left", "top", "right" 以及 "bottom" 屬性進行規定。 |
fixed | 生成絕對定位的元素,相對於瀏覽器窗口進行定位。元素的位置經過 "left", "top", "right" 以及 "bottom" 屬性進行規定。 |
relative | 生成相對定位的元素,相對於其正常位置進行定位。所以,"left:20" 會向元素的 LEFT 位置添加 20 像素。 |
static | 默認值。沒有定位,元素出如今正常的流中(忽略 top, bottom, left, right 或者 z-index 聲明)。 |
inherit | 規定應該從父元素繼承 position 屬性的值。 |
以上是較爲官方的定義,你能夠從中獲取到關於position
的一些基本操做,接下來讓咱們試圖從另外一個角度來理解position
.瀏覽器
position
是一種描述物體相對位置的藝術,它的核心是「參考座標系」的選擇佈局
正如咱們在現實生活中看到的那樣,咱們須要使用各類不一樣的「參考座標系」,來更方便準確地描述咱們身邊各類物體的相對位置。由於,咱們已經知道,若是單純依靠一個座標系來描述這個世界上的各個位置,這個世界將變得異常複雜。咱們須要使用不一樣的座標系,來幫住咱們簡化對位置的描述。spa
在咱們的網頁佈局中也是同樣,咱們不能只採用一個座標系來對網頁中的元素進行定位,那將使得咱們的網頁變得異常複雜且不易維護。咱們須要多個不一樣的座標系,來幫助咱們對網頁進行更好地佈局。css中的 position
,就是咱們俗稱的「定位」,就是定義了這麼一套規則,使得咱們能夠應用不一樣的座標系,來對頁面中的元素進行更好地佈局和管理。scala
反應在具體的規則當中,就是咱們熟知的static
,relative
,absolute
,fixed
。而它們最本質的區別就在於「參考座標系」的不一樣。其餘的一系列問題,例如典型的元素層級,均可以歸結爲position
所帶來的反作用。code
到這裏,你或許對position
有了一個不同的認識,接下來能夠嘗試着思考如下幾個問題orm
position
的反作用是什麼?position
的應用場景又是什麼?不知道?不要緊,或許如下的文章可以給你一點提示cdn
首先咱們須要討論的是position
的反作用,緣由很簡單,你手中有一個錘子,你總得知道這個錘子能幹什麼,不能幹什麼。咱們只有像如來佛祖瞭解悟空那樣瞭解position
,才能發揮出悟空(position
)的真正威力!
要分析position
的反作用,咱們或許能夠採用這樣的思路:
如下的組件均指開啓了
position
定位的元素,這裏把它稱爲組件
position
屬性對元素內部的元素會帶來什麼影響。簡稱對內的影響relative
和absolute
順着這個思路,接下來咱們來思考不一樣的position
屬性都會帶來什麼影響或反作用
absolute
和 relative
relative
和absolute
是咱們再熟悉不過的一對歡喜冤家,它們兩個常常是成對出現,產生的反作用也更多地來自於它們之間的組合。所以在這裏將它們放在一塊兒分析。
特性與反作用每每是相伴而生的。咱們先來回顧一下,這兩個屬性各有什麼特性?
position:absolute
元素具有的特性以下:
inline-block
的效果。鑑於本人的經驗限制,下面的反作用例子展現的也只是其中的一部分,若有更好的補充,歡迎在下方評論區中與你們一塊兒分享
position:relative
元素具有的特性以下:
relative
定位以後,基本不會影響其餘佈局z-index
來提高元素的層級relative
若是咱們單獨分析absolute
的反作用,咱們會把它簡單地歸結爲脫離文檔流,從而致使兩個最爲明顯的反作用:改變佈局和覆蓋。
可是我認爲這屬於它自己具有的特性,並非它的反作用。我以爲在現實應用中真正存在的反作用在於relative
和absolute
的共同應用所形成的問題,在這裏我把它稱做「深度relative
」。
所謂的「深度
relative
」,指的是relative
包裹的組件處於較深的層級,也就是被包裹的比較深,致使其中的absolute
組件要想不被其餘元素覆蓋,須要一級一級地往f父元素設置z-index
或者排查overflow
屬性。這個問題最關鍵的核心就是relative
組件層級太深。
這裏講得可能有點抽象,讓咱們一塊兒來看一個例子:
這是我在實際項目開發中遇到的一個典型的例子。簡單來說,就是點擊重選按鈕,在指定的位置跳出圖標選擇框,而且在窗口滾動時依然有效。具體效果以下圖所示:
就是這麼一個簡單的例子,固然以上是已經實現好的效果。若是你沒有遇到過相似的問題,你會以爲這個問題很簡單,使用relative
和absolute
就能輕鬆解決。可是,在這裏先賣個關子,以上的效果是使用fixed
實現的。
咱們首先使用咱們典型的relative
和absolute
來實現以上的效果,咱們能夠獲得以下的效果:
首先你會發現一個最爲明顯的問題,就是圖標選擇框被其餘元素蓋住了,這個時候的緣由就不少樣了,或許是由於它所在的祖先元素的元素層級沒有人家高,又或許是由於祖先元素設置了overflow:hidden
等等。這個時候若是咱們依然要堅持使用relative
和absolute
的解決方案,那咱們一般會採起的解決方案就是,一級一級的網上排查overflow:hidden
又或者是設置z-index
,直到解決問題爲止。
說到z-index
,這裏能夠簡單下使用方法。它僅在positon
屬性不爲static
時起做用。從position
從基礎能夠了解到absolute
和fixed
會讓元素脫離文檔流,這兩個修飾的元素默認層級天然比文檔流的要高,然而relative
則不會脫離文檔流,但當它設置了 TRBL 時它也會覆蓋文檔流,其默認層級天然也是比後者要高的,脫離文檔流和層級的概念不能混淆。
所謂同級,顧名思義,也就是同級間層級的比較,一個元素position
不爲static
後,若是不給它的z-index
設定值,默認爲0,由下圖能夠看到,A 元素設定了z-index
爲0,B元素未設定,E 元素設定了z-index
爲負數,按照順序 B 覆蓋住了 A,而E則被A蓋住。日後則是z-index
大的把小的覆蓋。
在此僅展現結構,css 代碼則省去。
<div id="1" style="position: absolute;z-index: 0">A</div>
<div id="2" style="position: absolute">B</div>
<div id="3" style="position: absolute;z-index: 1">C</div>
<div id="4" style="position: absolute;z-index: 2">D</div>
<div id="5" style="position: absolute;z-index: -1">E</div>
複製代碼
看到這個標題,你可能會問,這是啥意思?其實很簡單,它的意思是,要比較的元素再也不是簡單的同級概念,而是其中一個或二者都有祖先元素。看看下面這個代碼:
<div id="1" style="position:relative;z-index:2;">
<div id="1-1" style="position:relative;z-index:1;">A</div>
</div>
<div id="2" style="position:relative;z-index:1;">
<div id="2-1" style="position:relative;z-index:999;">B</div>
</div>
複製代碼
效果圖:
可見,A、B父元素的層級影響了相應的子元素的層級,就算 B 的z-index
設的再大,它的父元素的z-index
老是小於 A 的父元素的z-index
值,這時候不論 A 的z-index
怎麼變化,元素 A 就會像圖中同樣一直壓着 B,這就是從父原則。不過這裏要劃一下重點,這裏的父元素不必定要同級,換句話說,兩個元素間的層級比較,是相應的的同級祖先元素各自往下找到第一個position
不爲static
的的兩個元素之間的比較。舉個栗子,結構改爲下面這個結構,實現效果是同樣的。
<div id="1" style="position:relative;z-index:2;">
<div id="1-1" style="position:relative;z-index:1;">A</div>
</div>
<div>
<div id="2" style="position:relative;z-index:1;">
<div id="2-1" style="position:relative;z-index:999;">B</div>
</div>
</div>
複製代碼
以上講了這麼多,你或許以爲怎麼這麼繁瑣,要考慮這兒考慮那兒的,也會發現即便你用這種方法達到了你想要的效果,它也並不能從根本上解決問題。我一個簡單的小組件,你卻須要我去影響那麼多父級元素,誰知道會形成什麼意想以外的狀況。除了這個,設置過多的z-index
會致使頁面層級管理的混亂,使得頁面很難管理,全部有一個原則,要麼對z-index
作明文的規定,要麼就少用層級過深的z-index
。
我這裏有一種較好的解決方案,就是「fixed
組件」。若是你有更好的解決方案,歡迎在下方評論區中進行分享。
咱們都知道當元素設置了position:fixed
以後,該元素將具有如下的特性:
以上是咱們衆所周知的一些特性,其實根據以上的特性,咱們還能夠推出如下這些特性:
fixed
屬性,不須要再開啓父元素的定位,使得,減小了不少的z-index屬性的設置在下面的例子中,咱們只對「圖標組件」設置了
position:fixed
定位,頁面中的其餘大部分都是position:static
組件,所以能夠很輕鬆的解決原來的覆蓋問題,也不會影響其餘佈局,更不會形成z-index
管理混亂的問題。
fixed
組件的margin
,咱們能夠實現,fixed組件
相對於父元素進行定位一般咱們在應用
fixed
組件的時候,都要解決fixed
組件的滾動問題。一般fixed
組件不會隨着滾動條的滾動而滾動,可是咱們擁有強大的js,咱們能夠經過爲fixed
組件設置一個固定的margin-top
,而後經過js動態的控制這個值,使得它能夠相對父元素進行滾動。由於咱們都知道,margin
屬性調節的是box
之間的距離,fixed
組件脫了文檔流,但它依然是一個box,所以咱們可使用margin來調節fixed
組件與父元素之間的相對位置。
就拿上面的例子而言,具體代碼以下所示:
fixed
在固定定位元素的父元素上應用transform屬性,固定定位的元素會相對於父元素來定位
具體可參考如下這篇博文,簡單來講就是transform
屬性會對fixed
組件形成影響
Eric’s Archived Thoughts: Un-fixing Fixed Elements with CSS Transforms
講了這個多關於position
的反作用,我想到這裏你或許也早已經有了一套本身的範式,其實裏面的不少細節咱們都已經在前面提到過。在這裏我將分享一套屬於我本身的position
範式,學才疏淺,請不要見怪
relative
+absolute
或者「fixed
組件」的解決方案。若是組件層級較深,推薦使用「fixed
組件」的方式來進行定位;具體能夠參照上面提到過的圖標選擇框的例子。fixed
定位,例如右下角的小彈窗,固定的底部導航z-index
的嵌套使用fixed
定位時,要留意transform
屬性對它的影響