深刻理解 CSS 中的外邊距摺疊及 BFC

做爲一個前端工程師,在編寫 CSS 時外邊距摺疊及 BFC 都是常常遇到的狀況,今天就來作一下總結。css

外邊距摺疊

什麼是外邊距摺疊

在 CSS 中,兩個或者多個普通流中相鄰盒子的邊距在垂直方向上會發生摺疊的這種現象叫作外邊距摺疊。外邊距摺疊分爲父子外邊距摺疊及兄弟外邊距摺疊。html

示例1:父子外邊距摺疊

咱們給 child 添加了 margin-top,卻致使 body 總體下移。前端

示例2:兄弟外邊距摺疊

咱們給 child1 設置了 margin-bottom:20px,給 child2設置了 margin-top: 50px,但最終的展示效果確實 50px(注意:若是 margin 設置負值的話是什麼狀況的?能夠思考一下😯)css3

觸發外邊距摺疊的條件

那麼觸發外邊距摺疊的條件是什麼呢?W3C文檔裏已做出了說明,須要符合下面條件:git

  • 都是普通流中的元素且屬於同一個 BFC
  • 沒有被 padding、border、clear 或非空內容隔開
  • 兩個或兩個以上垂直方向的「相鄰元素」

注意這裏的「相鄰元素」多是兄弟節點也多是父子節點,好比:一個元素的 margin-top 和它的第一個普通流子元素的 margin-top;一個元素的 margin-bottom 和它下一個普通流兄弟的 margin-top;一個高度爲 auto 元素的 margin-bottom 和它的最後一個子元素的 margin-bottomgithub

如何避免外邊距摺疊

前面已經提到了觸發外邊距摺疊的條件,若是要避免外邊距摺疊只需破壞掉觸發的條件便可,好比建立一個 BFC。前端工程師

對於建立 BFC 的詳細方法,引用知乎用戶的回答就是:ide

根據 BFC 的定義,兩個元素只有在同一 BFC 內,纔有可能發生垂直外邊距的重疊,包括相鄰元素、嵌套元素。要解決 margin 重疊問題,只要讓它們不在同一個 BFC 內就行。對於相鄰元素,只要給它們加上 BFC 的外殼,就能使它們的 margin 不重疊;對於嵌套元素,只要讓父級元素觸發 BFC,就能使父級 margin 和當前元素的 margin 不重疊。佈局

固然也要規範寫法,好比設置 margin 時,儘可能使各個元素 margin 方向保持一致,這樣也能提升 CSS 代碼的可讀性。flex

那麼什麼是 BFC 呢?以及如何建立一個 BFC 呢?接下來就來詳細看一下。

BFC

什麼是 BFC

BFC(Block Formatting Context)即塊級格式化上下文,W3C 規範對此做了詳細的描述,翻譯過來大概以下:

  • 浮動元素和絕對定位元素,非塊級盒子的塊級容器(例如 inline-blocks, table-cells, 和 table-captions),以及 overflow 值不爲visiable 的塊級盒子,都會爲他們的內容建立新的 BFC(塊級格式上下文)。

  • 在 BFC 中,盒子從頂端開始垂直的一個接一個排列,兩個盒子之間的垂直間距由他們的 margin 值決定,在同一個 BFC 中,兩個相鄰塊級盒子的垂直外邊距會產生摺疊。

  • 在 BFC 中,每個盒子的左外邊緣會觸碰到容器的左邊緣,對於從右到左的格式來講,則觸碰到右邊緣。即便在浮動裏也是這樣的(儘管一個盒子的 line boxes 會由於浮動而收縮),除非這個盒子的內部建立了一個新的 BFC(因爲浮動,在這種狀況下盒子自己 將會變得更窄

Line Box: www.w3.org/TR/2002/WD-…

如何建立一個 BFC

經過上面的描述,建立一個 BFC 只需知足如下條件之一便可:

  • float 的值不爲 none
  • overflow 的值不爲 visible
  • position 的值不爲 static 或者 relative
  • display 的值爲 table-cell, table-caption, inline-block, flexinline-flex 其中之一

例如在本文開篇的第一個父子元素邊距摺疊的問題,咱們只需在父元素上增長 overflow: hidden 觸發 BFC 便可:

BFC 的使用

邊距摺疊的問題能夠用 BFC 來解決,但觸發 BFC 並非解決邊距摺疊的充分條件,還要獲得合理的運用,下面就是使用 BFC 來解決的一些問題。

使用 BFC 防止外邊距摺疊

對於兄弟元素,只要給它們加上 BFC 的外殼,對它們進行隔離,就能使它們的 margin 不折疊,例如:

<div class="parent">
  <div class="bfc">
    <div class="child child1">child1</div>
  </div>
	<!-- 本示例中只對其中一個加 bfc 外殼也能夠,保證不在同一個 bfc 中-->
  <div class="bfc">
    <div class="child child2">child1</div>
  </div>
</div>
複製代碼

對於父子元素,只要讓父級元素觸發 BFC,就能使父級的 margin 和當前元素的 margin 不折疊。

使用 BFC 防止高度塌陷

例如咱們在一個容器中,對其子元素進行了浮動處理,那麼因爲子元素脫離文檔流,容器的高度會發生塌陷,這個時候就能夠經過觸發容器的 BFC 來解決。

能夠對示例中的 parent 添加 overflow: hidden 來觸發 BFC,從而使容器高度恢復:

固然,對於相似問題咱們經常會經過 clearfix 清除浮動來解決,以保證普適性,不過 BFC 也不失爲一種不錯的解決辦法。

使用 BFC 防止「文字環繞」

好比以下示例,咱們但願 child2位於 child1 的右方,可是此時 child1child2 的一部分卻重合了,這並非咱們想要的效果。

這是因爲在 BFC 中,每個盒子的左外邊緣會觸碰到容器的左邊緣,對於從右到左的格式來講,則觸碰到右邊緣,即便在浮動裏也是這樣的(儘管一個盒子的 line boxes 會由於浮動而收縮)。而這裏 p 元素的文本部分就進行了收縮,爲浮動元素提供空間。

那麼此時爲了解決這個問題,只需觸發 p 元素的 BFC 便可,好比爲 p 元素添加一個 overflow: hidden

總結

  • 在 CSS 中,兩個或者多個普通流中相鄰盒子的邊距在垂直方向上會發生摺疊的這種現象叫作外邊距摺疊
  • 能夠經過合理的建立 BFC 解決外邊距摺疊的問題
  • BFC(Block Formatting Context)即塊級格式化上下文,具備 BFC 特性的元素是一個獨立的容器,容器裏面的元素不會在佈局上影響到外面的元素
  • 能夠經過以下方式建立 BFC:
    • float 的值不爲 none
    • overflow 的值不爲 visible
    • position 的值不爲 static 或者 relative
    • display 的值爲 table-cell, table-caption, inline-block, flexinline-flex 其中之一
  • BFC 能夠用來解決外邊距摺疊問題、高度塌陷問題以及「文字環繞」問題等

本文代碼示例地址:github.com/taroalan/bl…

相關參考


相關文章
相關標籤/搜索