【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的高度時,浮動元素也參與計算
- 預設情況下:html標籤(根元素)就是一個大的bfc;
- float屬性不為none; (left right)
- overflow不為visible; (auto scroll hidden )
- display為inline-block, table-cell, table-caption, flex, inline-flex
- position為absolute或fixed;
1. 高度塌陷
在浮動佈局中,父元素的高度預設是被子元素撐開的
當子元素浮動後,其會完全脫離文件流,子元素從文件流中脫離將會無法撐起父元素的高度,導致父元素的高度丟失
父元素高度丟失以後,其下的元素會自動上移,導致頁面的佈局混亂
2. BFC
BFC(Block Formatting Context)塊級格式化環境
- BFC 是一個 CSS 中的一個隱含的屬性,可以為一個元素開啟 BFC
- 開啟 BFC 該元素會變成一個獨立的佈局區域
元素開啟 BFC 後的特點:
- 不會被浮動元素覆蓋
- 父子元素外邊距不會重疊
- 可以包含浮動的元素
可以通過一些特殊方式來開啟元素的 BFC:
-
設定為浮動(不推薦):很明顯下方元素被覆蓋了,總不能讓所有元素都浮動吧
-
設定為行內塊元素(不推薦):不再獨佔一行,寬度變了,同時與下方元素產生了一點空隙
-
設定
overflow
為非visible
值:既沒有覆蓋元素,也保持了獨佔一方的特性(保持了寬度),與下方元素也保持了最初的間隙常用的方式為元素設定
overflow:hidden
(overflow: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 不為visible 和clip 的塊元素 |
display: flow-root |
|
contain: layout contain: content contain: paint
|
|
display: flex display: inline-flex 的直接子元素 |
Flex 項,如果它們本身既不是flex ,也不是grid 或table 容器 |
display: grid display: inline-grid 的直接子元素 |
Grid 項,如果它們本身既不是flex ,也不是grid 或table 容器 |
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 中的兩大難題
.clearfix::before,
.clearfix::after {
content: "";
display: table;
clear: both;
}
其中.clearfix::before
是為了解決外邊距重疊問題
.clearfix::before {
content: "";
display: table;
}
.clearfix::after
是為了解決高度塌陷問題
.clearfix::after {
content: "";
display: table;
clear: both;
}
兩者合在一起,就可以完美地解決高度塌陷和外邊距重疊這兩大“世紀難題”了