包含塊、BFC、margin collapse,bfccollapse
寫這篇文章的起因是源於這篇文章:談談面試與面試題 中關於position的討論,文中一開始就說的這句話:
面試的時候問個css的position屬效能刷掉一半的人這是啥情況……
其實這問題我本來打算的是可以順著一路扯到normal flow、containing block、bfc、margin collapse,base line,writing mode,bidi,這樣一路問下去的,奈何第一個問題(親我真的只問了position有哪些取值和行為啊)就悲劇了……
說到position,那麼稍微對css有所瞭解的必然能馬上說出它的四個屬性值:static 、relative、absolute、fixed。但是更深一步去討論,牽扯出諸如上文提到的normal flow、containing block、bfc、margin collapse,base line,writing mode,bidi,又有多少人能很好的回答完整呢,所以我想在此做一個自己的總結歸納。
1.normal flow
normal flow(正常流):正常流是預設的定位方式。任何沒有具體指定{position:absolute}或者{position:fixed}屬性以及沒有被浮動的元素都將預設獲得此屬性。
在這種方式裡,區塊層級元素在它們的包含塊裡一個一個垂直延伸,行內元素在它們的包含塊裡從左至右的水平排布。
值得注意的是,在正常流裡垂直邊距(vertical margin)是重疊的。也就是說,上下兩個塊級盒之間的邊距由它們之中邊距較大的元素決定,而不是他們的和!
1 <style> 2 div 3 { 4 width: 100px; 5 height: 100px; 6 border: 1px solid #00A4CC; 7 background-color: #3e8f3e; 8 } 9 .div110 {11 margin:20px 0;12 }13 .div214 {15 margin:40px 0;16 }17 </style>18 </head>19 20 <body>21 <div class="div1"></div>22 <div class="div2"></div>23 </body>
效果顯示如下:
div1和div2的垂直距離由大的margin決定,也就是div2的40px而不是二者之和60px。
其次,行內元素是會被折斷的,當寬度受到限制的時候,它會自動移動到下一行。這可能會產生一些難看的效果如果行內塊有邊框的話。看下面的效果:
1 <head> 2 <style> 3 div 4 { 5 width: 200px; 6 height: 100px; 7 border: 1px solid #00A4CC; 8 } 9 10 span11 {12 border: 2px solid #00ff00;13 }14 </style>15 </head>16 17 <body>18 <div>19 <span> 我會掉到下一行我會掉到下一行我會掉到下一行</span>20 </div>21 </body>
效果顯示如下:
2.containing block
containing block(包含塊):是視覺格式化模型的一個重要概念,它與框模型類似,也可以理解為一個矩形,而這個矩形的作用是為它裡麵包含的元素提供一個參考,元素的尺寸和位置往往是由該元素所在的包含塊決定的。也就是說一個元素盒子的位置和大小有時是通過相對於一個特定的長方形來計算的,這個長方形就被稱之為元素的 containing block。
一個元素的containing block按照以下方式定義:
5.如果沒有祖先,根項目盒子的內容邊界確定為 containing block。
名詞解釋:
視口:通過解析文檔,連續媒體(比如螢幕就是連續媒體,而印表機則是基於頁的媒體)給使用者產生一個視口(一個視窗或其它在螢幕上顯示的地區)。
根項目:源檔案中,每一個元素都有一個父元素,只有一個例外,它就是根項目。
padding edge:請參見:
舉個板栗:
1 <html> 2 <head> 3 <title>Illustration of containing blocks</title> 4 </head> 5 <body id="body"> 6 <div id="div1"> 7 <p id="p1">This is text in the first paragraph...</P> 8 <p id="p2">This is text 9 <em id="em1"> in the 10 <strong id="strong1">second11 </strong> paragraph.12 </em>13 </p>14 </div>15 </body>16 </html>
那麼,在沒有指定任何position的情況下,上方代碼的containng block確定方式為:
如果我們設定div1的position為:
1 #div1 { position: absolute;}
此時,div1 的 containing block 就不再是 body,它變成了初始 containing block(因為這裡還沒有具有 position 的祖先盒子)。
3.BFC
BFC(Block Formatting Context 塊格式化上下文):是W3C CSS 2.1 規範中的一個概念,在CSS3中被修改為flow root。格式化則表明了在這個環境中,元素處於此環境中應當被初始化,即元素在此環境中應當如何布局等。元素如果建立了BF麼BFC決定了如何對其內容進行定位,以及它與其他元素的關係和相互作用。
通俗理解:首先BFC是一個名詞,是一個獨立的布局環境,我們可以理解為一個箱子(實際上是看不見摸不著的),箱子裡面物品的擺放是不受外界的影響的。轉換為BFC的理解則是:BFC中的元素的布局是不受外界的影響(我們往往利用這個特性來消除浮動元素對其非浮動的兄弟元素和其子項目帶來的影響。)並且在一個BFC中,塊盒與行盒(行盒由一行中所有的內嵌元素所組成)都會垂直的沿著其父元素的邊框排列。
建立了BFC的元素會按照如下的方式對其子項目進行排列:
名詞解釋:
邊距摺疊:在CSS當中,相鄰的兩個盒子(可能是兄弟關係也可能是祖先關係)的外邊距可以結合成一個單獨的外邊距。這種合并外邊距的方式被稱為摺疊,並且因而所結合成的外邊距稱為摺疊外邊距。
摺疊的結果:
產生摺疊的必備條件:margin必須是鄰接的,且需要滿足如下條件:
那麼,什麼情況下會建立BFC:
值得注意的是,"display:table" 本身並不產生 "block formatting contexts"。但是,它可以產生匿名框, 其中包含 "display:table-cell" 的框會產生塊格式化上下文。
總之,對於 "display:table" 的元素,產生塊格式化內容相關的是匿名框而不是 "display:table"。
最後,是這些元素建立了塊格式化上下文,它們本身不是塊格式化上下文。
BFC的運用:消除浮動與多欄布局。
1.自適應兩欄布局
1 <style> 2 body { 3 position: relative; 4 } 5 6 .aside { 7 width: 100px; 8 height: 150px; 9 float: left;10 background: #f66;11 }12 13 .main {14 height: 200px;15 background: #fcc;16 }17 </style>18 <body>19 <div class="aside"></div>20 <div class="main"></div>21 </body>
效果如下:
根據BFC的規則:
每一個盒子的左外邊緣(margin-left)會觸碰到容器的左邊緣(border-left)(對於從右至左的格式來說,則觸碰到右邊緣)
所以,雖然存在浮動的元素aslide,但main的左邊依然會與包含塊的左邊相接觸。
因此,我們可以根據:
BFC的地區不會與float box重疊。
來通過觸發main產生BFC,實現自適應兩欄布局。
1 .main {2 overflow: hidden;3 }
當觸發main產生BFC後,這個新的BFC不會與浮動的aside重疊。因此會根據包含塊的寬度,和aside的寬度,自動變窄。效果如下:
2.清除內部浮動
1 <head> 2 <title>Clear float</title> 3 <style> 4 .container{ 5 margin: 30px auto; 6 width:600px; 7 height: 300px; 8 } 9 .wrapper{10 border:solid 3px #a33;11 }12 .main{13 width: 100px;14 height: 100px;15 background-color: #060;16 margin: 10px;17 float: left;18 }19 </style>20 </head>21 <body>22 <div class="container">23 <div class="wrapper">24 <div class="main"></div>25 <div class="main"></div>26 <div class="main"></div>27 </div>28 </div>29 </body>
希望的結果是:
但結果是:
父容器並沒有把浮動的子項目包圍起來,俗稱塌陷,為了消除這種現象,除了用傳統的偽類方法。根據
計算BFC的高度時,浮動元素也參與計算
還可以使父容器形成BFC,來清除浮動,簡單修改一下代碼:
<div class="wrapper"> 可以得到如下效果:
總結來說,BFC就是頁面上的一個隔離的獨立容器,容器裡面的子項目不會影響到外面的元素。反之也如此。
因為BFC內部的元素和外部的元素絕對不會互相影響,因此,當BFC外部存在浮動時,它不應該影響BFC內部Box的布局,BFC會通過變窄,而不與浮動有重疊。同樣的,當BFC內部有浮動時,為了不影響外部元素的布局,BFC計算高度時會包括浮動的高度。避免margin重疊也是這樣的一個道理。