CSS基礎——塊級元素、塊級盒子以及BFC

七秋發表於2018-02-09

最近在補CSS的基礎,看到盒子覺得理解起來比較混亂和困難,於是在網上查了好多資料,然後自己整理之後寫了下來。

這次寫一下塊級元素、塊級盒子以及BFC,如果有錯誤,歡迎大家指正 :)


在頁面中,每個元素被表示為一個矩形的方框,這就是盒子。

元素在頁面中會生成盒子。

盒子是CSS佈局中的基本單位,一張頁面是由一個或多個盒子組成的。盒子從內到外由內容(Content)、內邊距(Padding)、邊框(Border)和外邊距(Margin)組成,如下圖:

4-1

同時,盒子會為其子孫建立包含塊(containing block),用於計算內部盒子的大小及位置,由元素樣式的position屬性確定,這點之後的文章會討論。

盒子分為多種型別,在沒有CSS干預的情況下,它的型別由元素的型別決定,CSS的display屬效能夠修改它的型別。

塊級元素和盒子

display的值為block、table或者list-item的元素是塊級元素(block level element),它們會生成塊級盒子(block level box)並且參加塊級格式化上下文(Block Formatting Context,BFC)。

塊級盒子能夠設定寬和高,它被定義為放在其他盒子上面的盒子,對外佈局的影響主要表現為在它之前和之後的內容都不能和它處於同一行。

預設屬於塊級盒子的元素主要有:

  1. 地址(address);
  2. 塊引用(blockquote);
  3. 居中對其塊(center);
  4. 目錄列表(dir);
  5. 常用塊級(div);
  6. 定義列表(dl)、定義列表描述(dd)、定義列表宣告(dt);
  7. 互動表單(form)、表單控制組(fieldest);
  8. 大標籤(h1)、副標籤(h2)、3級標籤(h3)、4級標籤(h4)、5級標籤(h5)、6級標籤(h6);
  9. 水平分隔線(hr);
  10. 選單列表(menu);
  11. 可選指令碼內容(noscript);
  12. 排序列表(ol)、非排序列表(ul)、列表項(li);
  13. 段落(p);
  14. 格式化文字(pre);
  15. 表格(table);

塊級元素內巢狀

除了部分塊級元素之外,其他的塊級元素中能夠自由巢狀其他塊級元素:

  1. h1、h2、h3、h4、h5、h6、caption和p元素只能巢狀內聯元素;
  2. hr元素內不能巢狀其他元素;
  3. dt元素只能被巢狀在dl中;
  4. ul和ol元素的子級元素必須是li;
  5. dl元素的子級元素必須是dt或者dl元素;
  6. table元素的子級元素必須是caption或者thead、tbody、tfooter等元素,他們的子級必須是tr元素,之後才能是th或者td元素;

所以在日常使用中會遇到p元素巢狀div導致頁面錯誤的情況,如下圖:

<p>
  this is a p
  <div>this is a div</div>
</p>
複製程式碼

4-1

div標籤會將p標籤從中間斷開,<p></p>將會被分別識別為一個p元素來渲染。

塊級盒模型

塊級盒子模型分為W3C標準模型和IE標準模型,可以使用CSS的box-sizing屬性控制。

W3C標準模型

W3C標準模型的盒子模型對應的box-sizing屬性為content-box,它的width和height屬性是內容的寬和高,舉個例子:

div {
  width: 100px;
  height: 100px;
  padding: 15px;
  margin: 15px;
  border: 1px solid #000;
  box-sizing: content-box;
}
複製程式碼

4-2

從例子中可以看出,給div設定的width和height屬性僅僅只是content的寬和高,而不會把padding、border、margin計算在內。

IE標準模型

IE標準模型對應的box-sizing是border-box,它的width屬是邊框、內邊距和內容的寬的和,它的height屬是邊框、內邊距和內容的高的和,舉個例子:

div {
  width: 100px;
  height: 100px;
  padding: 15px;
  margin: 15px;
  border: 1px solid #000;
  box-sizing: border-box;
}
複製程式碼

4-3

從例子中可以看到,給div設定的寬度和高度都是100px,但是實際顯示出來的效果上,content只有68px,其他的32px被border和padding分走了。

塊級格式化上下文(Block Formatting Context,BFC)

BFC 是一塊獨立的渲染區域,只有它內部的塊級盒子參與它的佈局。這些塊級盒子的佈局方式不會受BFC外部佈局的影響,同時它們也不會影響BFC外部的佈局。

產生BFC

塊級格式化上下文中的“塊級”兩字並不是指BFC是由塊級元素產生的,而是指塊級元素會參加到BFC的佈局中來。

以下幾種元素能夠在其內部產生BFC:

  1. 根元素或其他包含它的元素

  2. 浮動元素,即float的值不為none的元素;

  3. 絕對定位元素,即position的值為fixed或absolute的元素;

  4. overflow不為visible的元素;

  5. 內聯塊元素,即display的值為inline-block的元素;

  6. 彈性元素,即display的值為flex或者inline-flex的元素;

  7. 網格元素,即display的值為grid或者inline-grid的元素;

  8. HTML預設的某些表格元素:

    • table,display的值為table;
    • th和td,display的值為table-cell;
    • caption,display的值為table-caption;
    • tr,display的值為table-row;
    • tbody,display的值為table-row-group;
    • thead,display的值為table-header-group;
    • tfooter,display的值為table-footer-group;
  9. 流式佈局根元素,display值為flow-root的元素;

  10. contain的值為layout、contain或者strict的元素;

  11. 多列容器,column-count或者column-width的值不為auto;column-count的值為1也是多列容器;

  12. column-span的值為all的元素始終會建立一個BFC;

BFC的佈局規則

  1. BFC內部的塊級盒子會在垂直方向一個接一個的堆放,並且相鄰的塊級盒子的外邊距(Margin)會摺疊,以最大的一個外邊距作為兩個盒子之間的距離;
  2. 計算BFC的高度時,它內部的浮動元素也會被計算進去;
  3. BFC的區域不會和浮動盒子相重疊;
  4. BFC內部每個元素的Margin Box的左邊都會和包含塊的Border Box的左邊相接觸;在從右往左格式化的情況下,則是每個元素的Margin Box的右邊都會和包含塊的Border Box的右邊相接觸;
  5. BFC在頁面上是一個獨立的區域,它內部的元素的佈局不會和外部元素的佈局產生相互影響;

下面讓我們來重點分析幾條:

外邊距摺疊

由於引數BFC佈局的是塊級盒子,所以不出意料的,每個塊級盒子佔據一行,在垂直方向一個接一個的堆放;

而由於BFC佈局規則第一條,相鄰塊級盒子之間的外邊距會摺疊,看個例子:

<div id="container">
  <div id="red"></div>
  <div id="yellow"></div>
  <div id="orange"></div>
</div>
複製程式碼
#container {
  overflow: auto;
  border: 1px solid #000;
  width: 100px;
}
#container > div {
  width: 50px;
  height: 50px;
  margin: 15px;
}
div#red {
  background-color: red;
}
div#yellow {
  background-color: yellow;
}
div#orange {
  background-color: orange;
  margin-top: 30px;
}
複製程式碼

4-4

就像例子中展示的那樣,我們先使用overflow: auto;使容器生成一個BFC區域,然後給區域裡的每個塊級元素設定外邊距,能夠明顯的看到,外邊距被摺疊了,而且orange的上側外邊距大於yellow的下側外邊距,因此這兩個塊級盒子的間距就以orange的上側外邊距為準。

阻止外邊距的摺疊的方法有很多,最簡單的方法就是將這幾個相鄰的盒子放在獨立的BFC容器中,使它們不再相鄰,修改下之前的例子:

<div id="container">
  <div>
    <div id="red"></div>
  </div>
  <div>
    <div id="yellow"></div>
  </div>
  <div>
    <div id="orange"></div>
  </div>
</div>
複製程式碼
#container {
  overflow: auto;
  border: 1px solid #000;
  width: 100px;
}
#container > div {
  overflow: auto;
}
#container > div > div {
  width: 50px;
  height: 50px;
  margin: 15px;
}
div#red {
  background-color: red;
}
div#yellow {
  background-color: yellow;
}
div#orange {
  background-color: orange;
  margin-top: 30px;
}
複製程式碼

4-5

可以看到,原本摺疊的外邊距展開了。

浮動元素導致的高度塌陷

在平時的使用中我們有時會遇到這種情況,在子元素被設定為浮動後,父元素會向上塌陷,這個子元素會突破父元素的區域,看個例子:

<div id="container">
  <div id="float"></div>
</div>
複製程式碼
#container {
  padding: 15px;
  background-color: #000;
  width: 100px;
}
#float {
  width: 50px;
  height: 100px;
  background-color: red;
  float: left;
}
複製程式碼

4-6

根據BFC佈局規則第三條,解決這種高度塌陷的方法就是將父元素設定為能夠生成BFC的元素,具體的實現方法有很多種,請參考文章之前的內容,修改一下例子:

#container {
  padding: 15px;
  background-color: #000;
  width: 100px;
  overflow: auto;
}
複製程式碼

4-7

這裡我們將容器的overflow屬性設定為auto,使它產生一個BFC區域,計算高度的時候能夠包含浮動的子元素。

不和浮動元素重疊

先來看個例子:

<div id="container">
  <div id="float"></div>
  <div id="child"></div>
</div>
複製程式碼
#container {
  padding: 15px;
  background-color: #000;
  width: 300px;
  overflow: auto;
}
#float {
  width: 50px;
  height: 100px;
  background-color: red;
  float: left;
}
#child {
  width: 100px;
  height: 120px;
  background-color: yellow;
}
複製程式碼

4-8

在這個例子裡,容器的第二個子元素就和浮動的第一個子元素重疊了,想要讓它們不重疊,根據BFC佈局的第三條,只要讓第二個子元素能夠生成BFC區域就可以了,修改一下例子:

#child {
  width: 100px;
  height: 120px;
  background-color: yellow;
  overflow: auto;
}
複製程式碼

4-9


本文同時收錄在我的GitHub部落格

CSS基礎——塊級元素、塊級盒子以及BFC

未經允許,請勿轉載!

相關文章