以下文章是我在網(wǎng)上收集的內(nèi)容,為了記錄自己的學(xué)習(xí)以及為了以后不到處找而記錄下來,如果對你有用,請感謝寫這些文章的前輩(特別是張鑫旭前輩),這些內(nèi)容肯定還有一些地方排版不好,比較粗糙,如果你對這個有建議的話,歡迎評論
BFC和IFC:
要想理解它們,必須首先理解FC,即 Formatting Context,它是W3C CSS2.1規(guī)范中的一個概念,定義的是頁面中的一塊渲染區(qū)域,并且有一套渲染規(guī)則,它決定了其子元素將如何定位,以及和其他元素的關(guān)系和相互作用
常見的Formatting Context 有:Block Formatting Context(BFC | 塊級格式化上下文) 和 Inline Formatting Context(IFC |行內(nèi)格式化上下文),當(dāng)然還有GridLayout Formatting Contexts(GFC |網(wǎng)格布局格式化上下文 )、Flex Formatting Contexts(FFC | 自適應(yīng)格式化上下文)分別對應(yīng)flex布局和grid布局,今天的主角是BFC、IFC,如果想了解GFC、FFC,可以自行查閱資料。
BFC布局規(guī)則:
- 內(nèi)部的Box會在垂直方向,一個接一個地放置。
- Box垂直方向的距離由margin決定。屬于同一個BFC的兩個相鄰Box的margin會發(fā)生重疊
- 每個元素的左外邊緣(margin-left), 與包含塊的左邊(border-left)相接觸(對于從左往右的格式化,否則相反)。即使存在浮動也是如此。除非這個元素自己形成了一個新的BFC。
- BFC的區(qū)域不會與float box重疊。
- BFC就是頁面上的一個隔離的獨立容器,容器里面的子元素不會影響到外面的元素。反之也如此。
- 計算BFC的高度時,浮動元素也參與計算
怎樣形成一個BFC?
- 根元素或其它包含它的元素
- 浮動 (元素的 float 不是 none)
- 絕對定位的元素 (元素具有 position 為 absolute 或 fixed)
- 元素具有 display: inline-block,table-cell, table-caption, flex, inline-flex
- 塊元素具有overflow ,且值不是 visible
用途:
- 清除浮動,子元素浮動,由于浮動破壞了正常的line boxes(ps:后面會講),父元素沒有了高度,導(dǎo)致高度塌陷,此時讓父元素形成BFC,按照上述BFC第六條規(guī)則,即可達(dá)到清除浮動的效果。
demo - 自適應(yīng)兩欄布局
demo - 防止垂直margin合并(mdn)
demo
IFC
IFC的line box(線框)高度由其包含行內(nèi)元素中最高的實際高度計算而來(不受到豎直方向的padding/margin影響)
IFC布局規(guī)則:
- 框會從包含塊的頂部開始,一個接一個地水平擺放。
- 擺放這些框的時候,它們在水平方向上的外邊距、邊框、內(nèi)邊距所占用的空間都會被考慮在內(nèi)。在垂直方向上,這些框可能會以不同形式來對齊:它們可能會把底部或頂部對齊,也可能把其內(nèi)部的文本基線對齊。能把在一行上的框都完全包含進(jìn)去的一個矩形區(qū)域,被稱為該行的行框。水平的margin、padding、border有效,垂直無效。不能指定寬高。
- 行框的寬度是由包含塊和存在的浮動來決定
IFC的 ‘line-height’ 與 ‘vertical-align’ 屬性以及基線:
介紹這些之前,我們先來張看一段代碼
<p>left<em>emem</em>right</p>
不要以為這段代碼簡單,他居然喪心病狂的涵蓋了四個內(nèi)容:
- 內(nèi)容區(qū)域(content-area) 是一種圍繞文字看不見的盒子,它的大小跟font-size有關(guān),可以理解成選中文字時的樣子
- 內(nèi)聯(lián)盒子(inline-boxes),他不會讓內(nèi)容成塊顯示,而是排成一行,<em>emem</em>,如果文字外部出現(xiàn)em、a等內(nèi)聯(lián)元素,則屬于內(nèi)聯(lián)盒子,如果是光禿禿文字就是匿名內(nèi)聯(lián)盒子,比如left/right
- 行框盒子(line-boxes)每一行就是一個行框盒子,它由一個個內(nèi)聯(lián)盒子組成,比如left<em>emem</em>right
-
p所在的包含盒子(containing-box),此盒子由一個個行框盒子組成,例如<p>left<em>emem</em>right</p>
line-box 的高度是根據(jù)子元素的高度計算出來的,而不是子元素的 content-area 的高度,content-area 的高度是由字體度量定義的,virtual-area 和 content-area 高度的差異叫做 leading。leading 的一半會被加到 content-area 頂部,另一半會被加到底部。因此 content-area 總是處于 virtual-area 的中間,計算出來的 line-height(也就是 virtual-area 的高度)可以等于、大于或小于 content-area。如果 virtual-area 小于 content-area,那么 leading 就是負(fù)的,因此 line-box 看起來就比內(nèi)容還矮了。由于content-area 的高度是由字體度量定義的,它是可變的,所以line-height是不確定的...
具體來說:
line-box 計算的一些細(xì)節(jié):
- 對于內(nèi)聯(lián)元素,padding 和 border 會增大 background 區(qū)域,但是不會增大 content-area(不是 line-box 的高度)。一般來說你無法再屏幕上看到 content-area。margin-top 和 margin-bottom 對兩者都沒有影響。
- 對于可替換內(nèi)聯(lián)元素(replaced inline elements)、inline-block 元素和 blockified 內(nèi)聯(lián)元素,padding、margin 和 border 會增大 height,因此會影響 content-area 和 line-box 的高度,行高決定了內(nèi)聯(lián)元素的高度
現(xiàn)在你知道為什么塊級元素可以設(shè)置寬高,margin、bottom,內(nèi)聯(lián)元素不能設(shè)置padding-top/padding-bottom。
line-height:normal;默認(rèn)屬性值,與用戶瀏覽器,且與元素字體有關(guān) 在body里里面初始化,確保一致性。可以這樣全局運(yùn)用:
body{
font:14px/1.4286 'microsoft yahei';
}
vertical:用來指定行內(nèi)元素(inline)或表格單元格(table-cell)元素的垂直對齊方式
vertical-align的默認(rèn)值就是基線,
那么什么是基線呢?

由一個問題開始。相信大家都碰到過一個div里面包裹一個圖片,但是div不能完全包裹圖片,還留有間隙,這個問題一直讓人很苦惱,
說這個問題之前,我們必須知道一個一個基礎(chǔ)知識,瀏覽器認(rèn)為每個 line-box 的起始位置都有一個寬度為 0 的字符(CSS 文檔將其稱為 strut),并將其納入 line-box 的高度的計算中,因此下次再當(dāng)我們碰到一個div包裹著圖片,一定要提醒自己假裝里面有文字,沒有也要裝著有,那么為什么要知道這個呢?因為每個內(nèi)聯(lián)元素都是默認(rèn)基線對齊,文字的基線在它的下面,由上文可知文字上下有一個1/2leading,所以文字與div有一個1/2leading,所以文字下面沒有和div的border接觸,所以圖片為了對齊這個基線,它就不得不有個間隙!
那么怎么解決呢?無非是解決基線或者line-height(1/2leading與line-height有關(guān))
- 讓vertical-align失效 圖片默認(rèn)是inline水平的,而vertical-align對塊狀水平的元素?zé)o感
圖片默認(rèn)是inline水平的,而vertical-align對塊狀水平的元素?zé)o感
- 使用其他vertical-align值:告別baseline, 取用其他屬性值,比方說bottom/middle/top都是可以的
- 直接修改line-height值。下面的間隙實際上是1/2leading,注意,我們可以通過改變行高改變這個值,行高足夠小,實際文字占據(jù)的高度的底部就很小,下面沒有了高度區(qū)域支撐,自然,圖片就會有容器底邊貼合在一起了。line-height:0;
- line-height為相對單位,font-size間接控制.font-size設(shè)置為0, 本質(zhì)上還是改變line-height值。
有時候我們經(jīng)常用vertical:middle:middle來居中,但是往往并沒有居中,這是為什么呢?vertical:middle:middle 的意思是「用父元素 baseline 高度加上父元素中 x-height 的一半的高度來對齊當(dāng)前元素的垂直方向的中點」。baseline 所處的高度跟字體有關(guān),x-height 的高度也跟字體有關(guān),所以 middle 對齊也不靠譜,大部分情況下,對齊的是 virtual-area,也就是一個不可見的高度。
一個inline-block元素,如果里面沒有inline內(nèi)聯(lián)元素,或者overflow不是visible,則該元素的基線就是其margin底邊緣,否則,其基線就是元素里面最后一行內(nèi)聯(lián)元素的基線。
說到position和float之前,先提一提.normal flow,normal flow(正常流):正常流是默認(rèn)的定位方式。任何沒有具體指定{position:absolute}或者{position:fixed}屬性以及沒有被浮動的元素都將默認(rèn)獲得此屬性。
在這種方式里,塊級元素在它們的包含塊里一個一個垂直延伸,行內(nèi)元素在它們的包含塊里從左至右的水平排布。
值得注意的是,在正常流里垂直邊距(vertical margin)是重疊的。也就是說,上下兩個塊級盒之間的邊距由它們之中邊距較大的元素決定,而不是他們的和,也就是說,外邊距合并是正常現(xiàn)象,但是因為不符合我們的預(yù)期,所以有時候會覺得不正常。
包含塊:是視覺格式化模型的一個重要概念,它與框模型類似,也可以理解為一個矩形,而這個矩形的作用是為它里面包含的元素提供一個參考,元素的尺寸和位置往往是由該元素所在的包含塊決定的。也就是說一個元素盒子的位置和大小有時是通過相對于一個特定的長方形來計算的,這個長方形就被稱之為元素的 containing block
一個元素的containing block按照以下方式定義:
用戶代理(比如瀏覽器)選擇根元素作為 containing block(稱之為初始 containing block)。
對于其它元素,除非元素使用的是絕對位置,containing block 由最近的塊級祖先元素盒子的內(nèi)容邊界組成。
如果元素有屬性 'position:fixed',containing block 由視口建立。
如果元素有屬性 'position:absolute',containing block 由最近的 position 不是 static 的祖先建立,按下面的步驟:
如果祖先是塊級元素,containing block 由祖先的 padding edge 形成。
如果祖先是內(nèi)聯(lián)元素,containing block 取決于祖先的 direction 屬性。如果 direction 是 ltr(左到右),祖先產(chǎn)生的第一個盒子的上、左內(nèi)容邊界是 containing block 的上方和左方,祖先的最后一個盒子的下、右內(nèi)容邊界是 containing block 的下方和右方。如果 direction 是 rtl(右到左),祖先產(chǎn)生的第一個盒子的上、右內(nèi)容邊界是 containing block 的上方和右方,祖先的最后一個盒子的下、左內(nèi)容邊界是 containing block 的下方和左方。
如果沒有祖先,根元素盒子的內(nèi)容邊界確定為 containing block。
外邊距合并:
- 兩個相鄰的外邊距都是正數(shù)時,折疊結(jié)果是它們兩者之間較大的值。
- 兩個相鄰的外邊距都是負(fù)數(shù)時,折疊結(jié)果是兩者絕對值的較大值。
- 兩個外邊距一正一負(fù)時,折疊結(jié)果是兩者的相加的和
產(chǎn)生折疊的必備條件:margin必須是鄰接的,且需要滿足如下條件:
- 必須是處于常規(guī)文檔流(非float和絕對定位)的塊級盒子,并且處于同一個BFC當(dāng)中。
- 沒有線盒,沒有空隙(clearance),沒有padding和border將他們分隔開
- 都屬于垂直方向上相鄰的外邊距,可以是下面任意一種情況:
- 元素的margin-top與其第一個常規(guī)文檔流的子元素的margin-top
- 元素的margin-bottom與其下一個常規(guī)文檔流的兄弟元素的margin-top
- height為auto的元素的margin-bottom與其最后一個常規(guī)文檔流的子元素的margin-bottom
- 高度為0并且最小高度也為0,不包含常規(guī)文檔流的子元素,并且自身沒有建立新的BFC的元素的margin-top和margin-bottom
值得注意的是,"display:table" 本身并不產(chǎn)生 "block formatting contexts"。但是,它可以產(chǎn)生匿名框, 其中包含 "display:table-cell" 的框會產(chǎn)生塊格式化上下文。
是這些元素創(chuàng)建了塊格式化上下文,它們本身不是塊格式化上下文
float:浮動float的本意是讓文字像流水一樣環(huán)繞浮動元素,因此就他能實現(xiàn)文字環(huán)繞效果。
特性:
- 浮動的包裹性——浮動就是個帶有方位的display:inline-block屬性,它與display:inline-block不同的地方在于浮動的方向性,display:inline-block僅僅一個水平排列方向,就是從左往右,而float可以從右往左排列,這就是兩者的差異。然而,我們又有多少情況需要元素從右往左排列呢?很少,所以,CSS中,沒有浮動這一屬性不是什么大不了的事情,它其實就那么回事。
- 浮動的破壞性——浮動破壞了正常的line boxes。文字之所以會環(huán)繞含有float屬性的圖片時因為浮動破壞了正常的line boxes,正常情況下,圖片自身就是個inline boxes,與兩側(cè)的文字inline boxes共同組成了line boxes,但是,一旦圖片加入了浮動,情況就完全變了。我認(rèn)為是浮動徹底破壞了img圖片的inline boxes特性,至少有一點我可以肯定,圖片的inline boxes不存在了,被惡魔附體,變身了,而這個惡魔就是浮動。一旦圖片失去了inline boxes特性就無法與inline boxes的文字排在一行了,其會從line boxes上脫離出來,跟隨自身的方位屬性,靠邊排列。
在目前的CSS的世界中,所有的高度都是有兩個CSS模型產(chǎn)生的,一個是box盒狀模型,對應(yīng)CSS為”height+padding+margin”,另外一個是line box模型,對應(yīng)樣式為”line-height”。前者的height屬性分為明顯的height值和隱藏的height值,所謂隱藏的height值是指圖片的高度,一旦載入一張圖片,其內(nèi)在的height值就會起作用,即使您看不到”height”這個詞。而后者針對于文字等這類inline boxes的元素(圖片也屬于inline boxes,但其height比line-height作用更兇猛,故其inline boxes高度等于其自身高度,對line-height無反應(yīng)),inline boxes的高度直接受line-height控制(改變line-height文字拉開或重疊就是這個原因),而真正的高度表現(xiàn)則是由每行眾多的inline boxes組成的line boxes(等于內(nèi)部最高的inline box的高度),而這些line boxes的高度垂直堆疊形成了containing box的高度,也就是我們見到的div或是p標(biāo)簽之類的高度了。所以,對于line box模型的元素而言,沒有inline boxes,就沒有高度了,而浮動卻恰恰做了這么齷齪的事情,其直接將元素的inline boxes也破壞了,于是這些元素也就沒有了高度。
浮動破壞了圖片的inline box,產(chǎn)生了兩個結(jié)果:一是圖片無法與文字同行顯示,脫離了其原來所在的line box鏈;二是沒有了高度(無inline box -> 無line box -> 無高度)。而這些結(jié)果恰恰是文字環(huán)繞圖片顯示所必須的。
我們可以拿浮動元素與絕對定位元素做對比或許可以幫助理解。與浮動元素一樣,絕對定位元素也具有“包裹性”,此“包裹性”適用于任何元素。那么,浮動元素與絕對定位元素的差別在哪里呢?我覺得最主要的差別在于:絕對定位的元素脫離了文檔流,而浮動元素依舊在文檔流中;而這造成的顯示上的差異就是:同處于文檔流中的文字實體不會與浮動元素重疊,而會與絕對定位元素重疊。這就是文字環(huán)繞顯示的重要原因之一:雖然圖片實際占據(jù)的高度為0,但是由于其寬度實體存在(包裹性),同樣是content area 實體的文字不會與之重疊(外部的容器盒子containing box(p,div,ul,li)會重疊
absolute:position:absolute與float:left兩者有兩大共性:包裹性,破壞性。
包裹性換種說法就是讓元素inline-block化,例如一個div標(biāo)簽?zāi)J(rèn)寬度是100%顯示的,但是一旦被absolute屬性纏上,則100%默認(rèn)寬度就會變成自適應(yīng)內(nèi)部元素的寬度
破壞性:float是欺騙父元素,讓其父元素誤以為其高度塌陷了,但float元素本身仍處于文檔流中,文字會環(huán)繞著float元素,不會被遮蔽,但absolute其實已經(jīng)不能算是欺騙父元素了,而是出現(xiàn)了層級關(guān)系。如果處于正常的文檔流中的父元素算是凡人的話,那absolute已經(jīng)得道成仙,用現(xiàn)在的話說已經(jīng)不在一個次元上。從父元素的視點看,設(shè)成absolute的圖片已經(jīng)完全消失不見了,因此從最左邊開始顯示文字。而absolute的層級高,所以圖片遮蓋了文字
relative:relative主要用于限制absolute,如果absolute元素沒有position:static以外的父元素,那將相對body定位,天空才是它的極限。而一旦父元素被設(shè)為relative,那absolute子元素將相對于其父元素定位,就好像一只腳上被綁了繩子的鳥
z-index:以下情況根本不需要設(shè)z-index:
- 讓absolute元素覆蓋正常文檔流內(nèi)元素(不用設(shè)z-index,自然覆蓋)
- 讓后一個absolute元素覆蓋前一個absolute元素(不用設(shè)z-index,只要在HTML端正確設(shè)置元素順序即可)
那什么時候需要設(shè)置z-index呢?當(dāng)absolute元素覆蓋另一個absolute元素,且HTML端不方便調(diào)整DOM的先后順序時,需要設(shè)置z-index: 1。非常少見的情況下多個absolute交錯覆蓋,或者需要顯示最高層次的模態(tài)對話框時,可以設(shè)置z-index > 1.
relative,absolute,fixed的區(qū)別:
- 絕對定位和浮動都會產(chǎn)生包裹性。block元素不指定width的話,默認(rèn)是100%,一旦讓該div浮動起來,立刻會像inline元素一樣產(chǎn)生包裹性,寬度會跟隨內(nèi)容自適應(yīng)。(這也是通常float元素需要手動指定width的原因)
- relative:生成相對定位的元素,相對于其正常位置進(jìn)行定位。
- 元素的位置通過left、right、top、button屬性進(jìn)行規(guī)定, 可以通過z-index進(jìn)行層次分級。
- 元素仍保持其未定位前的形狀,原本所占的空間仍將保留。
- 如果沒有定位偏移量,對元素本身沒有任何影響
- absolute:生成絕對定位元素。使元素脫離文檔流,并相對于其包含塊進(jìn)行定位,包含塊可能是文檔中的另一個元素或者是初始包含塊。
元素原先在正常文檔流中所占的空間會被后面元素占據(jù);
元素定位后生成一個塊級框,而不論原來它在正常流中生成何種類型的框;
設(shè)置了absolute一定要設(shè)置left或者top,否則他就按照文檔流的默認(rèn)位置(auto),若同時設(shè)置top/bottom或者left/right,那么只有top或者left有效
絕對定位元素的包含塊由離它最近的 ‘position’ 屬性為 ‘a(chǎn)bsolute’、’relative’ 或者 ‘fixed’ 的祖先元素創(chuàng)建。只要父級元素設(shè)置了position并且不是static(默認(rèn)既是static),那么設(shè)定了absolute的子元素即以此為包含塊(最近的)。如果都沒有定義,那么就相對于整個文檔body定位(注意不是相對于瀏覽器窗口定位)
相對定位一般都是配合絕對定位元素使用。
- fixed:生成絕對定位元素,相對于瀏覽器窗口(viewport)的定位。通常配合z-index一起來使用。比如說網(wǎng)頁上懸掛的聊天圖標(biāo)或者廣告就是用了fixed