CSS——讓“盒子”動起來:① 浮動

itsOli發表於2019-04-28
本文推薦 PC 端閱讀~

本文版權歸 “公眾號 | 前端一萬小時” 所有,未經授權,請勿轉載!
複製程式碼

CSS——讓“盒子”動起來:① 浮動

css_10
複製程式碼

CSS——讓“盒子”動起來:① 浮動

1. 浮動元素有什麼特徵?對父容器、其他浮動元素、普通元素、文字分別有什麼影響?
2. 清除浮動指什麼?如何清除浮動?兩種以上方法。
複製程式碼


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

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


1 為什麼需要“浮動”?

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

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

2 “浮動”是怎麼用的,有什麼表現效果?

2.1 放不下會換行

一個“浮動盒”會向左或向右移動,直到其外邊(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 {
  color: #fff;
  width: 100px;
  height: 100px;
  background: red;
  float: left;
/*?直接在你需要浮動的元素上加 float 屬性。*/

}
.box1{
  background: blue;
}
.box2{
  background: pink;
}
複製程式碼

CSS——讓“盒子”動起來:① 浮動

?對比:
?原始碼及效果展示
css

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

.box1{
  background: blue;
}
.box2{
  background: pink;
}
複製程式碼

CSS——讓“盒子”動起來:① 浮動

2.2 被卡住的情況

?原始碼及效果展示
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 {
  color: #fff;
  width: 100px;
  height: 100px;
  background: red;
  float: left;
}
.box1{
  background: blue;
  height: 120px;
}
.box2{
  background: pink;
}

/*依然站在瀏覽器的角度,從上往下渲染文件,
當依次渲染完 1、2 後,渲染 3 的時候,右邊放不下,
然後他要被擠下去,擠下去後它貼著 2 的下邊緣開始向左移動,
當移動碰到 1 右下角時,動不了了,1 被卡住了。
所以我們在設定高度不一樣時,會出現一個“卡住”的問題。*/
複製程式碼

CSS——讓“盒子”動起來:① 浮動

2.3 當浮動元素與文字有交集的時候

?原始碼及效果展示
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 {
  color: #fff;
  width: 100px;
  height: 100px;
  background: red;
  float: left;
}
.box1 {
  background: blue;
  width: 140px;
  height: 120px;
}
.box2 {
  background: pink;
}
複製程式碼

CSS——讓“盒子”動起來:① 浮動

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

?進一步驗證:
?原始碼及效果展示
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 是看不到這個浮動元素的,而文字看得到,並且圍繞這個浮動元素排列。
*/
/*?即展現出來的一個規則就是:
當一個普通元素碰到一個浮動元素後,這個普通元素看不見這個浮動元素,
但普通元素裡邊的文字看得見這個浮動元素。
*/
複製程式碼

CSS——讓“盒子”動起來:① 浮動

2.4 浮動元素脫離了普通流

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

⚠️注意:和 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 {
  color: #fff;
  width: 100px;
  height: 100px;
  background: red;
}
.box1 {
  background: blue;
  float: left;
  opacity: 0.6;
}
.box2 {
  background: pink;
  height: 110px;
  width: 110px;    
}
複製程式碼

CSS——讓“盒子”動起來:① 浮動

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

?原始碼及效果展示
html

<body>
<div class="box">這是div</div>
<span>這是span</span>
</body>
複製程式碼

css

.box {
  color: #fff;
  float: left;
  background: red;
}
span {
  color: #fff;
  float: left;
  background: blue;
  width: 100px;
  height: 50px;
  margin: 10px;
} 

/*?塊級元素設定浮動之後,它就呈現出 inline-block 這種感覺,他的寬度會收縮。*/
/*?行內元素設定為浮動之後,它就呈現了塊級的特性,
也有 inline-block 的感覺,就把行內元素變成可以設定寬高、margin 等,
但沒有居中這些東西。
*/
複製程式碼

CSS——讓“盒子”動起來:① 浮動

3 “浮動”的使用場景

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

?原始碼及效果展示——左側固定寬度,右側自適應
html

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

css

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

  background: blue;
  height: 500px;
}
複製程式碼

CSS——讓“盒子”動起來:① 浮動

?對比(右側固定寬度,左側自適應):
?原始碼及效果展示
html

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

css

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

  background: blue;
  height: 500px;
}
複製程式碼

CSS——讓“盒子”動起來:① 浮動

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

?原始碼及效果展示
html

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

css

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

  background: blue;
  height: 500px;
}
複製程式碼

CSS——讓“盒子”動起來:① 浮動

⚠️如果 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 {
  color: #fff;
  width: 150px;
  height: 400px;
  background: red;
  float: left;
}
.asidecolor: #fff;
  width: 150px;
  height: 400px;
  background: red;
  float: right;
}

.main {
  color: #fff;
  margin-right: 160px;
  margin-left: 160px;
/*加左右 margin 就把位置撐開了*/

  background: blue;
  height: 500px;
}
複製程式碼

11-11.png

3.3 利用浮動實現“導航條”

3.3.1 “導航條”靠左

?原始碼及效果展示
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 我們需要注意它的縫隙。
*/
複製程式碼

CSS——讓“盒子”動起來:① 浮動

3.3.2 “導航條”靠右

?原始碼及效果展示
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;
}
複製程式碼

CSS——讓“盒子”動起來:① 浮動

?對比:
?原始碼及效果展示
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;
}
複製程式碼

CSS——讓“盒子”動起來:① 浮動

4 清除“浮動”

4.1 為什麼要清除浮動?

因為任何東西有利有弊。

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

?原始碼及效果展示
html

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

css

.menu {
  color: #fff;
  width: 150px;
  height: 300px;
  background: red;
  float: left;
}
.asidecolor: #fff;
  width: 150px;
  height: 300px;
  background: red;
  float: right;
}
.main {
  color: #fff;
  margin-right: 160px;
  margin-left: 160px;
  background: blue;
  height: 200px;
}
#footer {
  color: #fff;
  background: grey;
}
複製程式碼

CSS——讓“盒子”動起來:① 浮動

文字能看見“浮動”.png

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

?原始碼及效果展示
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。*/
複製程式碼

CSS——讓“盒子”動起來:① 浮動

4.2 清除浮動的方法

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

?原始碼及效果展示
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;
}
/*?通過清除浮動來獲得一個普通元素,進而撐開這個父容器*/
複製程式碼

CSS——讓“盒子”動起來:① 浮動

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

1. ?對比

我們上邊是用一個造了一個 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 這個父容器。*/
複製程式碼

CSS——讓“盒子”動起來:① 浮動

2. ?再對比

?原始碼及效果展示
為了通用性,我們常常 .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;
}
複製程式碼

4.2.2 解決上邊由“浮動”帶來的問題

?原始碼及效果展示
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 {
  color: #fff;
  width: 150px;
  height: 300px;
  background: red;
  float: left;
}
.asidecolor: #fff;
  width: 150px;
  height: 300px;
  background: red;
  float: right;
}
.main {
  color: #fff;
  margin-right: 160px;
  margin-left: 160px;
  background: blue;
  height: 200px;
}
#footer {
  color: #fff;
  background: grey;
}


.clearfix::after {
/*?為了通用性,我們直接 clearfix ,
然後在 HTML 文件中,哪裡需要清除浮動,就直接加一個這個類名進去就可以了。*/

  content: '';
  display: block;
  clear: both;
}
複製程式碼

CSS——讓“盒子”動起來:① 浮動

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

  • 第一,inline-block——不需要清除浮動,簡單,在設定居中時更方便,適合子內容不多的元素水平排列。但要注意縫隙問題,以及對齊(上對齊);
  • 第二,float——沒縫隙問題,適合稍大的佈局。但需要解決的問題是父元素不會被撐開而導致的很多問題。

5 浮動和負 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,那就正好放上去。*/ 
}
複製程式碼

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

加油!

相關文章