《Oli的前端一萬小時》之:(12)讓「盒子」動起來——② 「定位」和 BFC
來自專欄 Oli的前端一萬小時
本知識學慣用時:4小時,總第60/10000小時
前言:這一篇我們主要探討「定位」和 BFC 是怎樣讓「盒子」動起來的。
學習方法依然是:打開 JS Bin ,拷貝代碼運行查看效果,然後搞定每一行代碼的前世今生。
一、什麼是「定位」?
「定位」就是通過設置 position 屬性的值來脫離正常的文檔流。
二、「定位」分哪幾類?
① 相對定位:
html
<div class="box1">1</div><div class="box2">2</div><div class="box1">3</div>
css
.box1, .box2 { width: 50px; height: 50px; border: 2px solid;}.box2 { position: relative;/* relative 是相對於它原本正常流的位置進行偏移,視覺上看它是移動了,但它原本所佔用的文檔流的空間是沒有變化的,對其他元素來說,它還是在那裡的,故其他元素位置是不會有變化的 */ top: 10px; left: 10px;}
② 絕對定位:
即你設置為絕對定位後,文檔流上的其他元素就看不見你了。就認為你不存在!如果存在多個絕對定位元素,那麼這些絕對定位元素也互相看不見。
html
<div class="box1">1</div><div class="box2">2</div><div class="box1">3</div>
css
.box1, .box2 { width: 50px; height: 50px; border: 2px solid;}.box2 { position: absolute; top: 10px; left: 10px;/*這個值是相對於誰做偏移呢?答:首先它會從自己的父元素裡邊去找,看看自己的父元素裡邊有沒有定位,這個定位包括 relative absolute fix ,如果有的話就相對於它;如果沒有的話,就再從父元素的父元素裡邊去找,如果有的話就相對於它;如果再沒有,就一直找到我們的 body 。*/}
-- (1)例:絕對定位的值是相對誰來取值做偏移?
html<div class="container"> <div class="box1">1</div> <div class="box2">2</div> <div class="box1">3</div></div>
css
html { border: 3px solid blue;/*最後,如果都沒有,那麼 box2 的絕對定位值就相對於這裡,到頭了。*/}body { margin: 40px; border: 1px solid red;/*其次,如果下邊 container 沒有 position ,而這裡有定位(relative absolute fixed),那麼 box2 的絕對定位值就相對於這裡: position: relative; */}container { margin-top: 40px; padding: 40px; background: yellow;/*首先,如果 box2 父元素這裡有定位(relative absolute fixed),那麼 box2 的絕對定位值就相對於這裡: position: relative; 而這裡用 relative 是最好的,因為一個元素本身設置 relative ,卻不設置值的話,就等同於沒設置。那他就依然在普通流中,它還是一個普通元素,那他自己的位置也沒發生變動,卻可以給其子元素作為相對的錨點。 */}.box1, .box2 { width: 50px; height: 50px; border: 2px solid;}.box2 { position: absolute; top: 0px; left: 10px;}/*??所以,我們在使用絕對定位的時候,一定要設置好定位的參考點(錨點)。一般來說,我們絕對定位的參考點都是相對於其父容器。所以原則上是:一個元素設置絕對定位 absolute ,那它的父容器設置定位為 relative */
-- (2)元素使用了絕對定位後,就如浮動一樣,有了「塊盒子」的特性。
-- (3)由於使用絕對定位之後,產生元素覆蓋的問題,z-index 可以解決元素之間覆蓋順序的問題,設置它的層疊順序。同級元素,數值越大,越靠近視覺點;不同父元素,只要父元素越大,那麼整體就越靠近視覺點,而不管其子元素大小情況。
顯示器顯示的圖案是一個二維平面,用 x 軸和 y 軸來表示位置屬性。
為了表示三維立體的概念,如顯示元素的上下層的疊加順序,引入了 z-index 屬性來表示 z 軸上一個元素在疊加順序上的上下立體關係。z-index 值較大的元素將疊加在 z-index 值較小的元素之上。對於未指定此屬性的定位對象,z-index 值為正數的對象會在其之上,而 z-index 值為負數的對象在其之下。z-index 屬性適用於定位元素(position 屬性值為 relative 或 absolute 或 fixed 的對象),用來確定定位元素在垂直於顯示屏方向(稱為 Z 軸)上的層疊順序,也就是說如果元素是沒有定位的,對其設置的 z-index 會是無效的。相同 z-index 誰上誰下?① 如果兩個元素都沒有定位發生位置重合現象或者兩個都已定位元素且 z-index 相同發生位置重合現象,那麼按文檔流順序,後面的覆蓋前面的。② 如果兩個元素都沒有設置 z-index,使用默認值,一個定位一個沒有定位,那麼定位元素覆蓋未定位元素父子關係處理:① 如果父元素 z-index 有效,那麼子元素無論是否設置 z-index 都和父元素一致,會在父元素上方;
② 如果父元素 z-index 失效(未定位或者使用默認值),那麼定位子元素的 z-index 設置生效
③ 固定定位:
position: fixed;
相對於瀏覽器的窗口進行定位。因此當滾動產生時,固定定位元素依然處於窗口的某個位置不動。
三、用「定位」還是用「浮動」?
① 大布局、自適應,用「浮動」————浮動一般和響應式結合的比較多;
② 小元素、固定寬高,用「定位」————一般只適用於一些很小的 icon ;
結合實際情況是關鍵。
比如說,網頁頭像上的未讀消息,我們一般都是選擇用「定位」才能很好的實現。凡是能蓋住其他東西的也是「絕對定位」。
四、小實戰:實現 navbar
html
<nav> <ul> <li><a href="#">首頁</a></li> <li><a href="#">作品</a></li> <li> <a href="#">更多</a> <ul class="child"> <li><a href="#">GitHub</a></li> <li><a href="#">博客</a></li> <li><a href="#">知乎</a></li> </ul> </li> </ul></nav>
css
* { margin: 0; padding: 0;}ul { list-style: none;}a { color: #333; text-decoration: none;}nav { width: 500px; margin: 10px auto 0; box-shadow: 0px 2px 4px 1px rgba(0,0,0,0.3);/*這裡邊的這幾個值:第一、二個值表示這個陰影的水平、垂直的偏移;4px 表示模糊度;1px 是這個模糊的一個延展;rgba 是這個模糊的顏色。*/}nav::after { content: ; display: block; clear: both;}/*由於我們用了浮動,我們需要清除浮動來撐開父容器。*/ nav>ul>li { position: relative;/*給下邊 .child 的絕對定位」偏移值「加一個「錨點」。*/ float: left;/*把這個選擇器層級里的 li 水平排列。*/}nav>ul>li:hover .child { display: block;}/* .child 默認是隱藏的,當我滑鼠放到「更多」這個 li 上的時候才顯示,並顯示為 block 。*/nav a { display: block; padding: 10px 10px;/*記著,我們要想點擊的範圍很大,我們是需要在 a 鏈接上來加 padding 的。如果在 li 上加 padding ,那麼點擊範圍依然在字上。*//*但要注意,由於 a 鏈接是個行內元素,所以如果這裡只單單加 padding ,那其實他的寬高是沒有變化的,只是背景色變大了,它會出現很多諸如「遮擋」的後果。故,我們需要讓其顯示為 block 。*//*我們沒有用 inline-block 是因為:用 inline-block 即它同時還是有行內特性,會導致"收縮"——即寬度由文本內容寬度決定。想要撐開,而不受內容寬度影響,那就需要用 block 。*/ min-width: 50px;/*這裡加了一個「最小的寬度」的用途是把這個 a 鏈接裡邊的文字內容撐開,使任何一個可點擊的文本都不換行。*/}nav a:hover { color: #fff; background: rgba(0,0,0,0.4);}nav .child { position: absolute;/*設置了絕對定位,我們才可以想把這個 .child 放哪裡就放哪裡,因為父容器發現不了它。而其他方式(比如浮動、或不用)是達不到理想的效果的。*/ top: 100%;/*100% 就表示按照 li 的高度。*/ box-shadow: 0px 2px 4px 1px rgba(0,0,0,0.3); display: none;/* .child 默認是"隱藏"的——display: none ,當我滑鼠放到「更多」這個 li 上的時候再顯示。*/}
五、BFC
相關前置知識,請先閱讀文章:
《(7)CSS 基本視覺格式化——① 「塊盒子」格式化》
《(8)CSS 基本視覺格式化——② 「行內盒子」格式化》
1.
在正常流中,盒子要麼屬於塊級格式化上下文,要麼屬於內聯格式化上下文。
每個渲染區域用 fomating context 表示,它決定了其子元素如何去定位,以及和其他元素的關係和相互作用。
BFC 全稱 Block Formating Context 。
2.
塊級格式化上下文說白了就是:對塊級元素——「他在渲染的時候遵循怎樣的規則,他們之間會有怎樣的作用」 這種機制的描述。換句話說,相當於我定了一種規則,那在普通流裡邊的這些元素,就按照我的這個規則進行布局。
3.
怎樣會產生一個塊級格式化上下文(BFC)呢?
① 同屬一個根元素;
都會遵循規則:比如說塊級元素撐滿父容器、父容器可以被子元素給撐開、產生外邊距合併、它的位置是從上到下。
② float 屬性不為 none;
如果一個元素增加了一個屬性叫 float ,那這個元素本身也產生了一個塊級格式化上下文。
那這個塊級格式化上下文跟他所在的這個大的格式化上下文有什麼關係呢?——答:我們可以認為在這個裡邊可以是他的一個小空間,裡邊的東西和外邊是沒有什麼影響的。換句話說,就像有一個隱形的界限一樣。
③ position 為 absolute 或 fixed ;
④ display 為 inline-block, table-cells,flex,或者 inline-flex;
⑤ overflow 不為 visible (為 hidden、auto、scroll)。
4.
我們之所以要了解這個 BFC ,是因為我們希望通過了解它的特性來實現我們需要的一些效果。或者當出現了某個問題的時候,我們能夠去解釋這個問題,知道是為什麼,進而解決它或找到替代方案。
5.
BFC 塊級格式化上下文的特性:
① 內部的 BOX 會在垂直方向,一個接一個的放置;
② BOX 垂直方向的距離由 margin 決定,屬於同一 BFC 的兩個相鄰 BOX 的 margin 會發生重疊每個元素的 margin box 的左邊,與包含塊 border box 的左邊相接觸(對於從左往右的格式化,否則相反)。即使存在浮動也是如此。
③ BFC 就是頁面上一個隔離的獨立容器,容器裡邊的子元素不會影響到外面的元素。反之也如此。
④ 計算 BFC 的高度時,浮動元素也參與計算。
(??對於③④特性,我們用的最多,我們常常去有意生成一個 BFC 也是為了能使用這兩個特性。)
6.
用 BFC 解決「邊距合併」問題:
① 對於兄弟元素:設置浮動,display:inline-block或使其父元素均形成 BFC 可防止邊距合併(如overflow:hidden);
② 對於父子間的元素:可以給父元素設置 border 或 padding 屬性來防止合併;
③ 對於空元素:設置 border 或 padding 屬性或 overflow:hidden;等(形成BFC)來防止合併。
後記:通過兩篇兄弟文章,我們算是讓「盒子」動了起來,那接下來 3 篇文章,我們就讓「這個可以動的盒子」更優雅的展示。加油!
歡迎繼續關注下文 :
(13)把這些「可以動的盒子」更優雅的展示——① 用「偽元素」讓展示變得更簡單
(本文版權歸 「Oli的前端一萬小時」 所有,轉載需說明來源)
推薦閱讀:
※VUE仿去哪網APP實戰活動,組隊做項目很棒棒少年團
※免費直播 | 2018,你最需要的前端學習指南&求職指南!飢人谷
※大齡電力汪前端學習路(HTML基礎篇)
※echarts文檔爬坑計劃(1)
※轉:CSS 專業技巧