水平有限,如果存在問題歡迎大家訪問我的博客批評(píng)指正.
正文
首先,'FC'肯定不是開封菜,而是Formatting context
的簡(jiǎn)稱.而在理解BFC等等概念之前,先讓我們了解一下'FC'與'Box'是什么?
-Formatting context
是 W3C CSS2.1 規(guī)范中的一個(gè)概念。它是頁面中的一塊渲染區(qū)域段多,并且有一套渲染規(guī)則礼饱,它決定了其子元素將如何定位垛玻,以及和其他元素的關(guān)系和相互作用福铅。最常見的 Formatting context 有 Block fomatting context (簡(jiǎn)稱BFC)和 Inline formatting context (簡(jiǎn)稱IFC)以及Flex formatting contexts(簡(jiǎn)稱FFC),最后還有一個(gè)GridLayout Formatting Contexts(GFC)倦卖。
Box
是 CSS 布局的對(duì)象和基本單位, 直觀點(diǎn)來說,就是一個(gè)頁面是由很多個(gè) Box 組成的钮惠。元素的類型和 display 屬性,決定了這個(gè) Box 的類型七芭。 不同類型的 Box素挽, 會(huì)參與不同的 Formatting Context(一個(gè)決定如何渲染文檔的容器),因此Box內(nèi)的元素會(huì)以不同的方式渲染狸驳。讓我們看看有哪些盒子:
- block-level box: display 屬性為 block, list-item, table 的元素预明,會(huì)生成 block-level box。并且參與 block fomatting context耙箍;
- inline-level box: display 屬性為 inline, inline-block, inline-table 的元素撰糠,會(huì)生成 inline-level box。并且參與 inline formatting context辩昆;
- run-in box: css3 中才有,暫未仔細(xì)研究過阅酪。
在我們一些使用場(chǎng)景觸發(fā)BFC是為了清除浮動(dòng)(我此次是因?yàn)榍宄?dòng)才引起的整體學(xué)習(xí)),所以我還得先講講清除浮動(dòng).
清除浮動(dòng)
為什么要清除浮動(dòng)?
清除浮動(dòng)主要是為了解決汁针,父元素因?yàn)樽蛹?jí)元素浮動(dòng)引起的內(nèi)部高度為0的問題
1.如下术辐,我給父div設(shè)置一個(gè)邊框,內(nèi)部放兩個(gè)div一個(gè)left 一個(gè)right施无,不設(shè)置浮動(dòng)辉词,則他們會(huì)默認(rèn)撐開父盒子
<body>
<div class="father">
<div class="left">left</div>
<div class="right">right</div>
</div>
<div class="footer">footer</div>
</body>
<style>
.father{
width: 60vw;
border: 5px solid #000;
}
.left{
width: 30vw;
height: 200px;
background: green;
}
.right{
width: 25vw;
height: 100px;
background: blue;
}
.footer{
width: 60vw;
height: 60px;
background: red;
border:3px solid rgb(194, 246, 6);
}
</style>
2.當(dāng)我給內(nèi)部?jī)蓚€(gè)div加上float屬性的時(shí)候
兩個(gè)div左右浮動(dòng)了,而父div因?yàn)闆]高度,只剩下黑色邊框了.紅色的footer元素也到最上邊去了.
那么:
當(dāng)父元素沒有高度的時(shí)候,如果子元素不浮動(dòng),就回按照子元素高度默認(rèn)撐開.但是當(dāng)子元素浮動(dòng)的時(shí)候,父元素就不會(huì)自動(dòng)撐開了.(ps:那么一個(gè)浮動(dòng),一個(gè)不浮動(dòng)呢?)
父組件沒了高度這就是高度坍塌
,要解決這個(gè)問題,我們首先就會(huì)想到clear
屬性,利用clear:both
來解決坍塌問題.
clear 屬性定義了元素的哪邊上不允許出現(xiàn)浮動(dòng)元素
- left 在左側(cè)不允許浮動(dòng)元素猾骡。
- right 在右側(cè)不允許浮動(dòng)元素较屿。
- both 在左右兩側(cè)均不允許浮動(dòng)元素。
- none 默認(rèn)值卓练。允許浮動(dòng)元素出現(xiàn)在兩側(cè)隘蝎。
- inherit 規(guī)定應(yīng)該從父元素繼承 clear 屬性的值。
但是具體清除浮動(dòng)的方式,我們也有好多種思路:
清除浮動(dòng)的方法
1. 標(biāo)簽法(不推薦)
<body>
<div class="father">
<div class="left">left</div>
<div class="right">right</div>
<div class="clear">我是一個(gè)標(biāo)簽</div>
</div>
<div class="footer">footer</div>
</body>
<style>
.father{
width: 60vw;
border: 5px solid #000;
}
.left{
width: 30vw;
height: 200px;
background: green;
}
.right{
width: 25vw;
height: 100px;
background: blue;
}
.footer{
width: 60vw;
height: 60px;
background: red;
border:3px solid rgb(194, 246, 6);
}
.clear{
clear: both;
}
</style>
當(dāng)我們的clear元素內(nèi)容為空時(shí),就可以借助它不允許兩邊有浮動(dòng)元素,那么只能放左右div下邊的限制來解決高度坍塌的問題.
- 優(yōu)點(diǎn):簡(jiǎn)單明了
- 缺點(diǎn):添加了無用的標(biāo)簽元素,渲染即使不影響,但是語義化比較差
所以不推薦
2.父級(jí)添加overflow屬性(不推薦)
通過觸發(fā)BFC方式襟企,實(shí)現(xiàn)清除浮動(dòng).
.fahter{
width: 60vw;
border: 5px solid #000;
overflow: hidden;
}
這種方式明眼一看很簡(jiǎn)單,但是會(huì)在有些操作時(shí)如果不自動(dòng)換行會(huì)直接隱藏掉,最簡(jiǎn)單的例子比如文字.
未設(shè)置overflow
設(shè)置overflow
- 優(yōu)點(diǎn):代碼簡(jiǎn)潔
- 缺點(diǎn):內(nèi)容增多的時(shí)候容易造成不會(huì)自動(dòng)換行導(dǎo)致內(nèi)容被隱藏掉嘱么,無法顯示要溢出的元素
所以也不推薦
3.使用after偽元素(推薦)
.father:after{
content: "";
display: block;
clear:both;
}
.father{
...
zoom: 1
}
優(yōu)點(diǎn):符合閉合浮動(dòng)思想,結(jié)構(gòu)語義化正確
缺點(diǎn):ie6-7不支持偽元素:after顽悼,使用zoom:1觸發(fā)hasLayout.
4.使用before和after雙偽元素(推薦)
.father:after,.father:before{
content: "";
display: table;
}
.father:after{
clear: both;
}
.father{
...
zoom: 1;
}
優(yōu)點(diǎn):代碼更簡(jiǎn)潔
缺點(diǎn):用zoom:1觸發(fā)hasLayout.
上面清除浮動(dòng)的方法里面隱約提到觸發(fā)BFC來達(dá)到目的,但是為什么觸發(fā)BFC就能清除掉浮動(dòng)呢.
不急,就讓我們從Formatting context
來慢慢展開.
FC(Formatting context)
BFC
BFC全稱是 block formatting context
曼振,也就是 塊級(jí)格式化上下文,是用于布局塊級(jí)盒的一塊 渲染區(qū)域蔚龙。
1. 觸發(fā)條件
- 根元素
- float的值不是none冰评。
- position的值不是static或者relative。
- display的值是inline-block木羹、inline-flex甲雅、flex解孙、flow-root、table-caption抛人、table-cell弛姜。
- overflow的值不是visible。
2. 渲染規(guī)則
- 內(nèi)部的Box會(huì)在垂直方向妖枚,從頂部開始一個(gè)接一個(gè)地放置
- Box垂直方向的距離由margin決定廷臼。屬于同一個(gè)BFC的兩個(gè)相鄰Box的margin會(huì)發(fā)生疊加
- 每個(gè)元素的margin box的左邊,與包含塊border box的左邊相接觸(對(duì)于從左往右的格式化绝页,否則相反)荠商。即使存在浮動(dòng)也是如此。
- BFC的區(qū)域不會(huì)與float box疊加续誉。
- BFC就是頁面上的一個(gè)隔離的獨(dú)立容器结啼,容器里面的子元素不會(huì)影響到外面的元素,反之亦然屈芜。
- 計(jì)算BFC的高度時(shí)郊愧,浮動(dòng)元素也參與計(jì)算。
1.3 規(guī)則一
這一點(diǎn)其實(shí)很好理解.一個(gè)接著一個(gè)往下排列.
1.3 規(guī)則二
我們看個(gè)案例井佑。
<body>
<div style="width:100px;height:100px;background:red;margin:20px;"></div>
<div style="width:100px;height:100px;background:blue;margin:20px;"></div>
</body>
按樣式代碼來看属铁,紅塊和藍(lán)塊之間間距應(yīng)該是40px。但實(shí)際上是20px躬翁。這就是BFC渲染規(guī)則的第二點(diǎn)(margin重疊)焦蘑。
因?yàn)锽FC的觸發(fā)條件之一就是根元素
,所以body
就是一個(gè)BFC容器盒发,紅塊和藍(lán)塊是同在body
下的相鄰塊級(jí)元素例嘱,其margin會(huì)生重疊,所以紅塊和藍(lán)塊之間間距只有20px宁舰。
1.3 規(guī)則三
第三點(diǎn)規(guī)則比較難理解我詳細(xì)解釋一下拼卵。首先要先理解包含塊的含義。
包含塊不是一個(gè)完整的box蛮艰,一個(gè)完整的box包含margin包含塊腋腮,border包含塊,padding包含塊壤蚜,content包含塊即寡。
包含塊有可能是box的content包含塊,也可能是box的padding包含塊袜刷。這取決于被包含塊所包含的元素的position
屬性聪富。
例如,如果某個(gè)元素position
屬性是absolute
著蟹,包含塊就是由它的最近的position
的值不是 static
的父級(jí)元素的padding包含塊組成墩蔓。
再例如梢莽,如果某個(gè)元素的position
屬性是static
或relative
,包含塊就是由它的父級(jí)元素的content包含塊钢拧。
如果某個(gè)元素的position
屬性是fixed
,包含塊就是視口炕横。
那么源内。BFC中的元素應(yīng)該與其自身的包含塊相接觸,而非與BFC相接觸份殿,這個(gè)包含塊有可能是BFC中的一部分膜钓,也有可能和bfc無關(guān)。
正常元素都是從左往右的格式化卿嘲,那么對(duì)元素的position屬性是absolute,right為0颂斜,或者元素的float的屬性為right,那么就是從右往左的格式化拾枣,元素的右邊緣和包含塊的右邊緣接觸沃疮。
元素H觸發(fā)生成BFC,其中有兩個(gè)元素A和元素B梅肤,元素A的float的屬性為left司蔬,那么元素A的左邊緣和元素H(也是元素A的包含塊)左邊緣接觸,如果元素B的float的屬性也為left姨蝴,元素B的左邊緣不和元素H的左邊緣接觸俊啼,而是和元素A的右邊緣接觸。這種情況就可以用規(guī)則中的“即使包含塊中的元素存在浮動(dòng)也是如此左医,除非其中元素再生成一個(gè)BFC”來解釋授帕,元素的float的屬性不為none會(huì)觸發(fā)生成BFC,所以這種情況是不矛盾的。
1.4 規(guī)則四
還是舉個(gè)例子:
<div>元素A</div>
<div>元素B</div>
當(dāng)你元素A添加float屬性后,元素A脫離文檔流扶平。
<div style='float:left;'>元素A</div>
<div>元素B</div>
正常情況下陷嘴,后面元知素B會(huì)與前道面的元素A重疊(因?yàn)閒loat導(dǎo)致A元素脫離文檔流不再占據(jù)原來的位置,后面元素會(huì)占據(jù)前面的位置搀矫,如圖)
這個(gè)時(shí)候給元素B加上overflow:hidden觸發(fā)BFC;
<div style='float:left;'>元素A</div>
<div style='overflow:hidden;'>元素B</div>
于是元素B 產(chǎn)生了BFC效果導(dǎo)致元素B收縮,不在占據(jù)元素A位置,如圖
兩欄自適應(yīng)問題的解決方案,有沒有!
1.5 規(guī)則五
這個(gè)規(guī)則屏轰,可以用來解決內(nèi)部元素浮動(dòng),導(dǎo)致父級(jí)元素的高度坍塌問題憋飞。其實(shí)很好理解,內(nèi)部元素與外部元素互不影響.
1.6 規(guī)則六
也很好理解,高度坍塌問題都解決了,浮動(dòng)元素的高度肯定要參與BFC的高度計(jì)算.
3霎苗、應(yīng)用場(chǎng)景
3.1、清除浮動(dòng)
在文章最初榛做,提到用clear:both來清除浮動(dòng)唁盏,我們也可以根據(jù)BFC的渲染規(guī)則第6點(diǎn)(計(jì)算BFC容器的高度時(shí)内狸,浮動(dòng)元素也參與計(jì)算)來清除浮動(dòng),解決高度坍塌的問題厘擂。
3.2昆淡、解決上下margin邊距問題
<body>
<div style="width:100px;height:100px;background:red;margin:20px;"></div>
<div style="width:100px;height:100px;background:blue;margin:20px;"></div>
</body>
我們利用BFC渲染規(guī)則第2點(diǎn)(屬于同一個(gè)BFC的兩個(gè)相鄰塊級(jí)元素的margin會(huì)發(fā)生重疊),那么不屬于同一個(gè)BFC的兩個(gè)相鄰塊級(jí)元素的margin就不會(huì)發(fā)生重疊刽严。
那么我們?cè)诘诙€(gè)div元素用一個(gè)div元素包裹起來昂灵,并用overflow:auto觸發(fā)其BFC。再看一下效果是不是不重疊了舞萄。
<body>
<div style="width:100px;height:100px;background:red;margin:20px;"></div>
<div style="overflow:auto">
<div style="width:100px;height:100px;background:blue;margin:20px;"></div>
</div>
</body>
3.3眨补、實(shí)現(xiàn)自適應(yīng)兩欄布局
自適應(yīng)兩欄布局,是一個(gè)主內(nèi)容區(qū)域和一個(gè)側(cè)邊欄區(qū)域組成倒脓,兩個(gè)區(qū)域的寬度都可以隨窗口大小自適應(yīng)撑螺。我們就可以利用BFC的規(guī)則四來實(shí)現(xiàn)這個(gè)需求.
詳見規(guī)則四案例.
4. 關(guān)于body元素的小問題
有時(shí)候我們?cè)赽ody上設(shè)置"display:hidden"不能觸發(fā)BFC.為什么呢?
w3c規(guī)定如果overflow不是visible的塊級(jí)元素將創(chuàng)建BFC。
但是又有一句提醒除非該值已經(jīng)擴(kuò)散到了視口
崎弃。
而w3c對(duì)于overflow也有定義:
- UAs需要將根元素上的overflow屬性置于視窗之上甘晤。
- overflow擴(kuò)散行為:當(dāng)根元素是html元素且overflow為visible,而且html元素有body作為其子元素饲做,UAs則需要將第一個(gè)body之上的overflow屬性應(yīng)用于視窗安皱。
- 用于視窗的overflow: visible將被解析為overflow: auto。
- overflow擴(kuò)散行為將導(dǎo)致body的overflow屬性為visible艇炎。
分析:
- html元素的overflow屬性默認(rèn)是visible,并且有body作為子元素,那么body的overflow屬性將被用于視窗,產(chǎn)生了擴(kuò)散行為.
- body元素的overflow被設(shè)置成了hidden,但是擴(kuò)散行為導(dǎo)致body元素屬性為visible.
所以
所以只能先將html元素的overflow屬性設(shè)置為hidden酌伊,再把body元素的overflow屬性設(shè)置為hidden,才能使body觸發(fā)BFC 。
IFC
IFC全稱是inline formatting context
缀踪,也就是 內(nèi)聯(lián)格式化上下文居砖,是用于布局內(nèi)聯(lián)元素盒子的一塊 渲染區(qū)域。
1驴娃、觸發(fā)條件
IFC的形成條件非常簡(jiǎn)單奏候,塊級(jí)元素中僅包含內(nèi)聯(lián)級(jí)別元素,需要注意的是當(dāng)IFC中有塊級(jí)元素插入時(shí)唇敞,會(huì)產(chǎn)生兩個(gè)匿名塊將父元素分割開來蔗草,產(chǎn)生兩個(gè)IFC。
2疆柔、渲染規(guī)則
- 子元素水平方向橫向排列咒精,并且垂直方向起點(diǎn)為元素頂部。
- 子元素只會(huì)計(jì)算橫向樣式空間旷档,【padding模叙、border、margin】鞋屈,垂直方向樣式空間不會(huì)被計(jì)算范咨,【padding故觅、border、margin】渠啊。
- 在垂直方向上输吏,子元素會(huì)以不同形式來對(duì)齊(vertical-align)
- 能把在一行上的框都完全包含進(jìn)去的一個(gè)矩形區(qū)域,被稱為該行的行框(line box)替蛉。行框的寬度是由包含塊(containing box)和與其中的浮動(dòng)來決定贯溅。
- IFC中的“l(fā)ine box”一般左右邊貼緊其包含塊,但float元素會(huì)優(yōu)先排列灭返。
- IFC中的“l(fā)ine box”高度由 CSS 行高計(jì)算規(guī)則來確定盗迟,同個(gè)IFC下的多個(gè)line box高度可能會(huì)不同坤邪。
- 當(dāng) inline-level boxes的總寬度少于包含它們的line box時(shí)熙含,其水平渲染規(guī)則由 text-align 屬性值來決定。
- 當(dāng)一個(gè)“inline box”超過父元素的寬度時(shí)艇纺,它會(huì)被分割成多個(gè)boxes怎静,這些 boxes 分布在多個(gè)“l(fā)ine box”中。如果子元素未設(shè)置強(qiáng)制換行的情況下黔衡,“inline box”將不可被分割蚓聘,將會(huì)溢出父元素。
3盟劫、應(yīng)用場(chǎng)景
- 水平居中:當(dāng)一個(gè)塊要在環(huán)境中水平居中時(shí)夜牡,設(shè)置其為inline-block則會(huì)在外層產(chǎn)生IFC,通過text-align則可以使其水平居中侣签。
- 垂直居中:創(chuàng)建一個(gè)IFC塘装,用其中一個(gè)元素?fù)伍_父元素的高度,然后設(shè)置其vertical-align:middle影所,其他行內(nèi)元素則可以在此父元素下垂直居中蹦肴。
FFC
FFC全稱是flex formatting context
, 也就是 靈活格式化上下文,是用于布局彈性容器的一塊 渲染區(qū)域猴娩。
1阴幌、觸發(fā)條件
父級(jí)元素設(shè)置display:flex或者`display:inline-flex
2、渲染規(guī)則`
可以看阮一峰的Flex 布局教程:語法篇卷中,講的非常詳細(xì)矛双。
要注意一點(diǎn)。生成FFC后蟆豫,其子元素的float背零、clear和vertical-align屬性將失效。
3无埃、應(yīng)用場(chǎng)景
1徙瓶、自動(dòng)撐開頁面高度毛雇,底欄總是出現(xiàn)在頁面的底部
<style>
.wrap{
display:flex;
padding:0;
margin:0;
min-height:100vh;
flex-direction:column;
}
.main{
flex-grow:1;
}
</style>
<body class="wrap">
<header style="line-height:50px;background:red;color:#fff;text-align:center">頭部</header>
<main class="main">內(nèi)容</main>
<footer style="line-height:50px;background:#eeeeee;color:#333;text-align:center">底欄</footer>
</body>
2、經(jīng)典的圣杯布局
<style>
.wrap {
display: flex;
padding: 0;
margin: 0;
min-height: 100vh;
flex-direction: column;
}
header,
footer {
flex: 0 0 50px;
}
.content {
display: flex;
flex: 1
}
.main {
flex: 1;
}
.nav,
.ads{
flex: 0 0 100px;
background:green;
}
.nav{
order:-1;
background:yellow;
}
</style>
<body class="wrap">
<header style="line-height:50px;background:red;color:#fff;text-align:center">頭部</header>
<div class="content">
<main class="main">內(nèi)容區(qū)</main>
<nav class="nav">側(cè)邊導(dǎo)航</nav>
<aside class="ads">側(cè)邊欄</aside>
</div>
<footer style="line-height:50px;background:#eeeeee;color:#333;text-align:center">底欄</footer>
</body>
GFC
GFC全稱是gridLayout formatting context
侦镇,也就是 網(wǎng)格布局格式上下文灵疮,是用于布局網(wǎng)格容器的一塊 渲染區(qū)域。
1壳繁、觸發(fā)條件
當(dāng)為一個(gè)元素設(shè)置display值為grid的時(shí)候震捣,此元素將會(huì)獲得一個(gè)獨(dú)立的渲染區(qū)域,我們可以通過在網(wǎng)格容器(grid container)上定義網(wǎng)格定義行(grid definition rows)和網(wǎng)格定義列(grid definition columns)屬性各在網(wǎng)格項(xiàng)目(grid item)上定義網(wǎng)格行(grid row)和網(wǎng)格列(grid columns)為每一個(gè)網(wǎng)格項(xiàng)目(grid item)定義位置和空間闹炉。
2. 應(yīng)用場(chǎng)景
那么GFC有什么用呢蒿赢,和table又有什么區(qū)別呢?首先同樣是一個(gè)的表格渣触,但GridLayout會(huì)有更加豐富的屬性來控制行列羡棵,控制對(duì)齊以及更為精細(xì)的渲染語義和控制。
最后:關(guān)于zoom知識(shí)的擴(kuò)展
zoom:1是針對(duì)ie的屬性,可以激活hasLayout屬性,關(guān)于hasLayout
haslayout 是Windows Internet Explorer渲染引擎的一個(gè)內(nèi)部組成部分嗅钻。在InternetExplorer中皂冰,一個(gè)元素要么自己對(duì)自身的內(nèi)容進(jìn)行計(jì)算大小和組織,要么依賴于父元素來計(jì)算尺寸和組織內(nèi)容养篓。為了調(diào)節(jié)這兩個(gè)不同的概念秃流,渲染引擎采用了 hasLayout 的屬性,屬性值可以為true或false柳弄。當(dāng)一個(gè)元素的 hasLayout屬性值為true時(shí)舶胀,我們說這個(gè)元素有一個(gè)布局(layout)
要想更好的理解 css, 尤其是 IE 下對(duì) css 的渲染碧注,haslayout 是一個(gè)非常有必要徹底弄清楚的概念嚣伐。大多IE下的顯示錯(cuò)誤,就是源于 haslayout应闯。如果它設(shè)置成了true纤控,它就不得不去渲染它自己,因此元素不得不擴(kuò)展去包含它的流出的內(nèi)容碉纺。例如浮動(dòng)或者很長(zhǎng)很長(zhǎng)的沒有截?cái)嗟膯卧~船万,如果haslayout沒有被設(shè)置成true,那么元素得依靠某個(gè)祖先元素來渲染它骨田。這就是很多的ie bugs誕生的地方耿导。
參考文章:
紅塵煉心-四年前端在CSS面試上跪了