(11)讓「盒子」動起來——① 浮動

(11)讓「盒子」動起來——① 浮動

來自專欄 Oli的前端一萬小時

本知識學慣用時:5小時,總第56/10000小時


前言:前10篇文章,我們基本上都是在用「理論」學習「理論」,那從這篇開始,我們試著用「實踐」來學習理論,然後又用於實踐。

一個原則:把代碼拷貝到 JS Bin 上,對照效果搞懂每行代碼的「是什麼」、「為什麼」、「怎麼樣」?


一、為什麼需要「浮動」?

假設我們需要有個東西,然後他的排版不是依照盒模型的定義——從上往下依次排列,而是從左到右這種結構,那麼我們需要考慮到使用「浮動」。

例如一個網站的頭部,一部分在左邊,一部分在右邊。首先「部分」的表示我們會用 div ,而 div 是塊級元素,按理說它會從上到下,佔據一整行,不可能整列排列。那這個時候我們就需要「浮動」。

二、「浮動」是怎麼用的,有什麼表現效果?

① 放不下會換行:

一個浮動盒會向左或向右移動,直到其外邊(outer edge)挨到包含塊邊沿或者另一個浮動盒的外邊。如果沒有足夠的水平空間來浮動,它會向下移動,直到空間合適或者不會再出現其它浮動了。

html

<div class="ct"> <div class="box box1">1</div> <div class="box box2">2</div> <div class="box box3">3</div></div>

css

.ct { width: 280px; height: 300px; border: 1px solid; margin: 100px;}.box { width: 100px; height: 100px; background: red; float: left;/* 直接在你需要浮動的元素上加 float 屬性。*/}.box1{ background: blue;}.box2{ background: pink;}

??對比:

.ct { width: 280px; height: 300px; border: 1px solid; margin: 100px;}.box { width: 100px; height: 100px; background: red; float: right;}/*站在瀏覽器的角度看,它會挨著順序依次渲染*/.box1{ background: blue;}.box2{ background: pink;}

② 被卡住的情況:

html

<body><div class="ct"> <div class="box box1">1</div> <div class="box box2">2</div> <div class="box box3">3</div></div></body>

css

.ct { width: 280px; height: 300px; border: 1px solid; margin: 100px;}.box { width: 100px; height: 100px; background: red; float: left;}.box1{ background: blue; height: 120px;}.box2{ background: pink;}/*依然站在瀏覽器的角度,從上往下渲染文檔,當依次渲染完 1、2 後,渲染 3 的時候,右邊放不下,然後他要被擠下去,擠下去後它會和2的下邊緣開始向左移動移動碰到1右下角時,動不了了,1 被卡住了。所以我們在設置高度不一樣時,會出現一個「卡住」的問題。*/

③ 當浮動元素與文本有交集的時候:

html

<body><div class="ct"> <div class="box box1">1</div> <p>挨到包含塊邊沿或者另一個浮動盒的外邊。如果存在行盒,浮動盒的外 top (邊)會與當前行盒的 top (邊)對齊。如果沒有足夠的水平空間來浮動,它會向下移動,直到空間合適或者不會再出現其他浮動了。 </p> <div class="box box2">2</div> <div class="box box3">3</div></div></body>

css

.ct { width: 280px; height: 300px; border: 1px solid; margin: 100px;}.box { width: 100px; height: 100px; background: red; float: left;}.box1 { background: blue; width: 140px; height: 120px;}.box2 { background: pink;}

??可以得到:

普通流中的一個元素,如果沒有設置定位和浮動,那它和浮動元素在一起之後,它會被浮動元素所遮擋。

??進一步驗證:

css

.ct { width: 280px; height: 300px; border: 1px solid; margin: 100px;}.box { width: 100px; height: 100px; background: red; float: left;}.box1 { background: blue; height: 120px; width: 140px; opacity: 0.2;}.box2 { background: pink;}/*但裡邊的文字並沒有被這個浮動元素所遮擋,那他呈現的這個效果是:這個段落 p 是看不到這個浮動元素的,而文字看得到,並且圍繞這個浮動元素排列。*//*即展現出來的一個規則就是:當一個普通元素碰到一個浮動元素後,這個普通元素看不見這個浮動元素,但普通元素裡邊的文字看得見這個浮動元素。*/

④ 浮動元素脫離了普通流:

脫離普通流是指:他的父容器在去計算寬高的時候,發現不了浮動元素。即,父容器不會被裡面的浮動元素撐開;

——注意:和 absolute 不一樣。

html

<div class="ct"> <div class="box box1">1</div> <div class="box box2">2塊盒看不見浮動的 box1,但我是文本我能看見</div> <div class="box box3">3</div></div>

css

.ct { width: 280px; height: 300px; border: 1px solid; margin: 100px;}.box { width: 100px; height: 100px; background: red;}.box1 { background: blue; float: left; opacity: 0.6;}.box2 { background: pink; height: 110px; width: 110px; }

⑤ 塊級元素浮動寬度收縮,行內元素浮動以塊級特性去呈現:

html

<body><div class="box">z這是div</div><span>這是span</span></body>

css

.box { float: left; background: red;}span { float: left; background: blue; width: 100px; height: 50px; margin: 10px;} /*塊級元素設置浮動之後,它就呈現出 inline-block 這種感覺,他的寬度會收縮。*//*行內元素設置為浮動之後,它就呈現了塊級的特性,也有 inline-block 的感覺,就把行內元素變成可以設置寬高,margin 等,但沒有居中這些東西。*/

三、「浮動」的使用場景

① 兩欄布局(左側固定寬度,右側自適應; 右側固定寬度,左側自適應)

html

<div class="aside">側邊欄固定寬度</div><div class="main">內容區塊自適應寬度</div>

css

.aside { width: 150px; height: 400px; background: red; float: left;}.main { margin-left: 160px;/*表示左邊的這 160px 的範圍我不用了*/ background: blue; height: 500px;}

??對比(右側固定寬度,左側自適應):

html

<div class="aside">側邊欄固定寬度</div><div class="main">內容區塊自適應寬度</div>

css

.aside { width: 150px; height: 400px; background: red; float: right;}.main { margin-right: 160px;/*表示右邊的這 160px 的範圍我不用了*/ background: blue; height: 500px;}

② 三欄布局——兩側寬度固定,中間自適應(注意 HTML 中的 menu aside main 的順序!)

html

<div class="menu">側邊欄固定寬度</div><div class="aside">側邊欄固定寬度</div><div class="main">內容區塊自適應寬度</div>

css

.menu { width: 150px; height: 400px; background: red; float: left;}.aside { width: 150px; height: 400px; background: red; float: right;}.main { margin-right: 160px; margin-left: 160px;/*加左右 margin 就把位置撐開了*/ background: blue; height: 500px;}

??如果 HTML 中的 menu aside main 的順序變了:

html

<div class="menu">側邊欄固定寬度</div><div class="main">內容區塊自適應寬度</div><div class="aside">側邊欄固定寬度</div><!--順序一旦變了,後邊的 aside 就會跳行,跑到下邊去了。原因:假設我是瀏覽器,我需要對著 html 來畫出對應的圖像,首先畫 menu ,結合其樣式,左浮;但這裡我們遇到了 main ,這個 main 是一個塊級元素,它會佔據一整行的寬度;那接下來的 aside 就只有在 main 的基礎上往右下流動。-->

css

.menu { width: 150px; height: 400px; background: red; float: left;}.aside { width: 150px; height: 400px; background: red; float: right;}.main { margin-right: 160px; margin-left: 160px;/*加左右 margin 就把位置撐開了*/ background: blue; height: 500px;}

③ 利用浮動實現「導航條」:

-- 靠左

html

<ul class="navbar"> <li><a href="#">1首頁</a></li> <li><a href="#">2產品</a></li> <li><a href="#">3服務</a></li> <li><a href="#">4關於</a></li></ul>

css

.navbar { list-style: none;}.navbar>li { float: left; margin-left: 15px;}/*當然我們用 inline-block 也可以實現效果,但不同方式需要注意的問題不一樣:使用浮動我們需要注意撐開容器;而用 inline-block 我們需要注意它的縫隙。*/

-- 靠右

html

<body><ul class="navbar"> <li><a href="#">1首頁</a></li> <li><a href="#">2產品</a></li> <li><a href="#">3服務</a></li> <li><a href="#">4關於</a></li></ul></body>

css

.navbar { float: right;/*把 ul 整體進行右浮動*/ list-style: none;}.navbar>li { float: left;/*但 ul 裡邊的東西都是靠左的*/ margin-left: 15px;}

??對比:

html

<ul class="navbar"> <li><a href="#">1首頁</a></li> <li><a href="#">2產品</a></li> <li><a href="#">3服務</a></li> <li><a href="#">4關於</a></li></ul>

css

.navbar { list-style: none;}.navbar>li { float: right;/*直接改這裡是不行的,因為站在瀏覽器的立場是按文檔順序來渲染的*/ margin-left: 15px;}

四、清除「浮動」

① 為什麼要清除浮動?因為任何東西有利有弊。

第一,對後續元素位置產生影響(渲染時,因為塊元素看不見,但裡邊的文字看的見):

html

<div id="content"> <div class="menu">側邊欄固定寬度</div> <div class="aside">側邊欄固定寬度</div> <div class="main">內容區塊自適應寬度</div></div><div id="footer">我是 footer,但我的樣式出現了問題</div>

css

.menu { width: 150px; height: 300px; background: red; float: left;}.aside { width: 150px; height: 300px; background: red; float: right;}.main { margin-right: 160px; margin-left: 160px; background: blue; height: 200px;}#footer { background: grey;}

第二,父容器高度計算出現問題:

html

<ul class="navbar"> <li><a href="#">1首頁</a></li> <li><a href="#">2產品</a></li> <li><a href="#">3服務</a></li> <li><a href="#">4關於</a></li></ul>

css

.navbar { list-style: none; border: 1px solid #ccc; /*加一個背景色也沒效果: background: pink;*/}.navbar>li { float: left; margin-left: 15px;}/*由於浮動元素脫離了文檔流,所以他的父元素是看不見他的。這裡對於 navbar 來說,他認為裡邊沒有什麼 li 來把它撐開,因為 li 已經浮動了,那沒有東西撐開它,它就會認為高度為 0。*/

② 清除浮動的方法:

-- 清除浮動實現的原理和方法

html

<ul class="navbar"> <li><a href="#">1首頁</a></li> <li><a href="#">2產品</a></li> <li><a href="#">3服務</a></li> <li><a href="#">4關於</a></li> <li class="clear"></li><!-- 想解決這個沒辦法撐開的問題,那麼就要求這個源文檔中要有一個沒有被浮動的的元素——普通元素。--> </ul>

css

.navbar { list-style: none; border: 1px solid #ccc;}.navbar>li { float: left; margin-left: 15px;}.navbar .clear { float: none; clear: left;}/*通過清除浮動來獲得一個普通元素,進而撐開這個父容器*/

· 清除浮動(clear:left)——這個 clear 可以用在任何元素上,不管你是不是浮動元素。要求該盒的 top border 邊位於源文檔(就是 html 文檔結構中)中在此之前的元素形成的所有左浮動盒的 bottom 外邊下方(如果沒有左浮動盒,那你清除左浮動也就沒有意義)。

· 清除浮動(clear: right)——要求該盒的 top border 邊位於源文檔中在此之前的元素形成的所有右浮動盒的 bottom 外邊下方。

· 清除浮動(clear: both)——只要源文檔中該盒前邊有浮動元素,那麼就在這個浮動元素下方。

??對比:

我們上邊是用一個造了一個 li 來實體化普通元素,那我們可否有更簡化的方法——偽元素(偽元素的一個作用就是去代替標籤)。

html

<ul class="navbar"> <li><a href="#">1首頁</a></li> <li><a href="#">2產品</a></li> <li><a href="#">3服務</a></li> <li><a href="#">4關於</a></li></ul>

css

.navbar { list-style: none; border: 1px solid #ccc;}.navbar>li { float: left; margin-left: 15px;}.navbar::after { content: ;/*寫了一個元素,你必須要有 content */ display: block;/*注意這裡如果沒有這個 block ,是不會生效的,因為寫了 after ,只是表示是一個匿名的行盒,即一個字元串。然而他必須是塊級元素,他才會下去。*/ clear: both;}/*用偽元素這樣寫就是表示:我在源文檔 navbar 的最後生成了一個 block 元素,然後清除浮動,他就會位於浮動盒子的下方,進而撐開了 navbar 這個父容器。*/

??再對比:

為了通用性,我們常常 .clearfix::after ——就是為了修復浮動所產生的問題。

html

<ul class="navbar clearfix"><!--凡是需要清除浮動的地方我們都可以加一個這個樣式就可以通用--> <li><a href="#">1首頁</a></li> <li><a href="#">2產品</a></li> <li><a href="#">3服務</a></li> <li><a href="#">4關於</a></li></ul>

css

.navbar { list-style: none; border: 1px solid #ccc;}.navbar>li { float: left; margin-left: 15px;}.clearfix::after {/*為了通用性,我們直接 clearfix ,然後在 HTML文檔中,哪裡需要清除浮動,就直接加一個這個類名進去就可以了。*/ content: ; display: block; clear: both;}

-- 解決上邊由「浮動」帶來的問題

html

<div id="content" class="clearfix"><!--意思就是:這三個元素下邊還有一個元素,然後這個元素會在這三個元素的下方,進而就會撐開這個 content 。--> <div class="menu">側邊欄固定寬度</div> <div class="aside">側邊欄固定寬度</div> <div class="main">內容區塊自適應寬度</div></div><div id="footer">我是 footer,但我的樣式出現了問題</div>

css

.menu { width: 150px; height: 300px; background: red; float: left;}.aside { width: 150px; height: 300px; background: red; float: right;}.main { margin-right: 160px; margin-left: 160px; background: blue; height: 200px;}#footer { background: grey;}.clearfix::after {/*為了通用性,我們直接 clearfix ,然後在 HTML文檔中,哪裡需要清除浮動,就直接加一個這個類名進去就可以了。*/ content: ; display: block; clear: both;}

??小總結:所以以後我們想去實現一個水平布局,就有了兩種方法:

第一,inline-block——不需要清除浮動,簡單,在設置居中時更方便,適合子內容不多的元素水平排列。但要注意縫隙問題,以及對齊(上對齊);

第二,float——沒縫隙問題,適合稍大的布局。但需要解決的問題是父元素不會被撐開而導致的很多問題。

五、浮動和負 margin

兩個浮動元素,如果因放不下導致其中一個下移,對下移的元素設置負 margin 值大於自身的寬度可將其上移。

html

<div class="container"> <div class="box box1">box1</div> <div class="box box2">box2</div></div>

css

* { margin: 0}.container { width: 400px; height: 400px; border: 1px solid red;}.box1 { width: 300px; height: 100px; background: pink; float: left;}.box2 { width: 110px; height: 100px; background-color: red; float: left; margin-left: -10px; /* 瀏覽器計算的時候就相當於寬度減去這個 10 ,然後就是100,那就正好放上去。*/ }


後記:下篇我們討論與「浮動」對應的「定位」是怎樣讓「盒子」動起來的。加油!後續文章都是重中之重,每一篇都乾貨滿滿!

歡迎繼續關注下文 :

(12)讓「盒子」動起來——② 「定位」和 BFC

(本文版權歸 「Oli的前端一萬小時」 所有,轉載需說明來源)


推薦閱讀:

用vue實現簡易的音樂webApp
移動web前端學習
緩存(持續更新)
看別人吵架對你來說應該是好事兒
前端周刊

TAG:CSS | 前端開發 | 前端入門 |