1. 程式人生 > 其它 >【Web前端HTML5&CSS3】08- 高度塌陷與BFC

【Web前端HTML5&CSS3】08- 高度塌陷與BFC

高度塌陷與 BFC

BFC:             全稱:Block Formatting Content;是一個與上下文無關的獨立的渲染區域;(塊級格式化上下文)             是一種佈局規則:
  •  內部的Box會在垂直方向,一個接一個地放置。
  •  Box垂直方向的距離由margin決定。屬於同一個BFC的兩個相鄰Box的margin會發生重疊(按照最大margin值設定)
  •  每個元素的margin box的左邊, 與包含塊border box的左邊相接觸
  •  BFC的區域不會與float box重疊。
  •  BFC就是頁面上的一個隔離的獨立容器,容器裡面的子元素不會影響到外面的元素。
  •  計算BFC的高度時,浮動元素也參與計算
                        開啟BFC的條件:
  •    預設情況下:html標籤(根元素)就是一個大的bfc;
  •    float屬性不為none;      (left  right)
  •    overflow不為visible;    (auto  scroll  hidden )
  •    display為inline-block, table-cell, table-caption, flex, inline-flex
  •    position為absolute或fixed;
                注: 在合適的情況下,使用合適的屬性開啟bfc;

1. 高度塌陷

在浮動佈局中,父元素的高度預設是被子元素撐開的

當子元素浮動後,其會完全脫離文件流,子元素從文件流中脫離將會無法撐起父元素的高度,導致父元素的高度丟失

父元素高度丟失以後,其下的元素會自動上移,導致頁面的佈局混亂

2. BFC

BFC(Block Formatting Context)塊級格式化環境

  • BFC 是一個 CSS 中的一個隱含的屬性,可以為一個元素開啟 BFC
  • 開啟 BFC 該元素會變成一個獨立的佈局區域

元素開啟 BFC 後的特點:

  • 不會被浮動元素覆蓋
  • 父子元素外邊距不會重疊
  • 可以包含浮動的元素

可以通過一些特殊方式來開啟元素的 BFC:

  • 設定為浮動(不推薦):很明顯下方元素被覆蓋了,總不能讓所有元素都浮動吧

  • 設定為行內塊元素(不推薦):不再獨佔一行,寬度變了,同時與下方元素產生了一點空隙

  • 設定overflow為非visible:既沒有覆蓋元素,也保持了獨佔一方的特性(保持了寬度),與下方元素也保持了最初的間隙

    常用的方式為元素設定overflow:hiddenoverflow:auto也是 ok 的) 開啟其 BFC, 以使其可以包含浮動元素

    overflow:scroll 會有滾動條,可能並不需要的,所以不太推薦

    不過,這種方式也存在一定問題,如下,overflow並沒有完全清除 div2 佈局上受到的影響

總結

  • 可以通過變成浮動元素,來防止自身被浮動元素覆蓋(有點“以毒攻毒”那味了)
  • 可以設定行內塊,來防止自身及其他元素被浮動元素覆蓋(如果說浮動是“獨善其身”,那行內塊就有點“兼濟天下”的意思)
  • 可以設定overflow屬性,包含浮動元素(既“獨善其身”,又“兼濟天下”,但仍有缺陷)

我這裡大概翻譯了一下,並整理了一份表格,應該看起來更直觀一點(有些概念因為還沒有學習,翻譯和理解有誤的地方還望諒解)

元素或屬性 說明
<html> 文件根元素
float: left
float: right
浮動元素(float不為none
position: absolut
position: fixed
絕對定位元素
display: inline-block 行內塊元素
display: table-cell 表格單元,預設值
display: table-caption 表格標題,預設值
display: table
display: table-row
display: table-row-group
display: table-header-group
display: table-footer-group
display: inline-table
匿名的表格單元,分別是 HTML 表格、錶行、表體、表頭和表腳的預設值
overflow: hidden
overflow: scroll
overflow: auto
overflow不為visibleclip的塊元素
display: flow-root  
contain: layout
contain: content
contain: paint
 
display: flex
display: inline-flex的直接子元素
Flex 項,如果它們本身既不是flex,也不是gridtable容器
display: grid
display: inline-grid的直接子元素
Grid 項,如果它們本身既不是flex,也不是gridtable容器
column-count不為auto
column-width不為auto
Multicol 容器,包含column-count: 1
column-span: all 應該總是建立一個新的格式化上下文,即使column-span: all元素不在 multicol 容器中

3. clear

我們這裡設計三個兄弟元素,對前兩個元素進行float的浮動屬性設定,看下效果

由於 box1 的浮動,導致 box3 位置上移也就是 box3 受到了 box1 浮動的影響,位置發生了改變(注意,這裡文字並沒有被覆蓋,《09-浮動》一節說過浮動的特點,其中第 7 點就是“文字環繞”的問題)

如果我們不希望某個元素因為其他元素浮動的影響而改變位置,可以通過clear屬性來清除浮動元素對當前元素所產生的影響

clear作用:清除浮動元素對當前元素所產生的影響(本質是為元素新增一個margin-top屬性,值由瀏覽器自動計算)

可選值:

  • left 清除左側浮動元素對當前元素的影響
  • right 清除右側浮動元素對當前元素的影響
  • both 清除兩側中影響較大一側元素的影響(注意,這裡不是同時清除兩側的影響)

4. after

我們學習了上面知識後,瞭解了高度塌陷問題的解決方式,其中主要有

  • 通過overflow: hidden等可以為元素開啟 BFC

  • 通過clear: both等可以清除浮動對元素產生的影響

同時也瞭解到,這兩種方式都有一定的弊端和隱患。那有沒有一種更好的方式去解決高度塌陷的問題呢?

答案當然是:有!

我們直接上效果圖

Q1:這裡使用了一個偽元素選擇器::after,那有人會問了,跟在 box2 下直接定義一個 box3 有什麼區別呢?

A:我們知道,網頁的結構思想是:結構+表現+行為。在 box2 下直接定義一個 box3,屬於結構;而使用偽元素選擇器,屬於表現

而高度塌陷問題屬於表現問題,定義 box3 的目的是為了撐起 box1 的內容,屬於表現,而不是結構,所以在 css 中定義::after更符合網頁的程式設計思想

Q2:為什麼需要使用display: block呢?

A:因為預設情況下,::after偽元素是一個行內元素,如果不轉為塊元素,將仍然撐不起 box1 的高度

5. clearfix

我們在前面《06-盒模型》一節中說過垂直佈局中邊距重疊的問題:相鄰的垂直方向外邊距會發生重疊現象

如上圖所示,子元素設定了一個margin-top之後,父元素跟隨子元素一起進行了移動

即我們之前說的父子元素間相鄰外邊距,子元素會傳遞給父元素(上外邊距)

聰明的小夥伴已經想到了,用剛才說的偽元素選擇器啊

好,我們先來看下效果

貌似是沒有任何變化,到底是什麼地方不對呢?

我們再來回顧下使用after偽元素的心路歷程:

  • 使用無內容的 box3 撐起 box1 ==》表現代替結構(::after代替 box3)
  • clear清除浮動對元素產生的影響(還記得clear的原理麼?)

其實就是給元素設定了一個margin-top屬性,不過這個在開發者工具中是看不到的

既然如此,就相當於在 box2 下面新增一個 box3,然後給 box3 設定一個margin-top屬性

到此為止,

∵ 相鄰的垂直方向外邊距 這個條件仍然滿足

∴ 會發生重疊現象這個結論也依然成立

具體點就是,父子元素間相鄰外邊距,子元素會傳遞給父元素(上外邊距),表現為 box1 和 box2 同步往下移動

那我們應該怎麼做才能解決這個問題? 憑你們樸素的情感,應該怎麼判? 當然就是讓上述條件不滿足唄!

怎麼能夠不滿足?當然是讓兩個元素垂直外邊距不相鄰啊!

好,多說無益,我們直接上程式碼看效果!

我們用了before偽元素選擇器,目的當然是讓 box1 和 box2 的外邊距不相鄰,但是好像並沒有效果

我們再換成display: inline-block屬性看看

好像是解決了父元素佈局的問題,但是子元素怎麼還往下跑了一段距離? 是誰給的勇氣?

因為inline-block兼顧行內元素和塊元素的特點,既可以設定寬高也不獨佔一行

在沒有設定寬高時,會存在一個預設高度,所以inline-block仍然行不通

還有一個屬性,display: table

Bingo!實現了我們最終想要的效果

Q1:為什麼沒有使用 clear 屬性?

A:不是說了嗎?clear是為了清除浮動對佈局的影響,我們現在沒有浮動的元素啊,我們要討論的也不是浮動的問題

Q2:display 不是還有一個none屬性麼,為什麼不用呢?

A:none屬性是不佔據位置,但是也不能讓元素相鄰的外邊距分離啊

Q3:為什麼table值就可以呢?

A:這個問題問的非常好,算是問到點上了!我們上面在講開啟 BFC 的一些方法的時候,也提到了該屬性。而且,應該牢記的是,元素開啟 BFC 後的其中一個特點就是 父子元素外邊距不會重疊。當然,這裡也需要合理選擇偽元素選擇器,使其外邊距不相鄰才行

另外,總結一下:

  • 高度塌陷問題,一般用::after
  • 外邊距重疊問題,一般用::before

不知道到這裡,大家能不能想明白這兩件事情

那麼問題來了,有沒有一個兩全其美的辦法,既可以解決高度塌陷,又可以解決外邊距重疊呢?

當然有!clearfix 這個樣式就可以同時解決高度塌陷和外邊距重疊的問題

當你在遇到這些問題時,直接使用clearfix這個類即可,他就可以幫你輕鬆搞定 css 中的兩大難題

CSS
.clearfix::before,
.clearfix::after {
  content: "";
  display: table;
  clear: both;
}

其中.clearfix::before是為了解決外邊距重疊問題

CSS
.clearfix::before {
  content: "";
  display: table;
}

.clearfix::after是為了解決高度塌陷問題

CSS
.clearfix::after {
  content: "";
  display: table;
  clear: both;
}

兩者合在一起,就可以完美地解決高度塌陷和外邊距重疊這兩大“世紀難題”了