前言
盒子模型作為CSS基礎中的基礎,曾一度以為掌握了IE和W3C標準下的塊級盒子模型即可,但近日在學習行級盒子模型時發現原來當初是如此幼稚可笑。本文嘗試全面敘述塊級、行級盒子模型的特性。作為近日學習的記錄。
何為盒子模型?
盒子模型到底何方神聖居然可以作為CSS的基礎。聞名不如見面,上圖了喂!
再來張切面圖吧!
下面我們以 <div></div> 為栗子。 <div></div> 標籤被瀏覽器解析後會產生div元素並添加到document tree中,但CSS作用的對象並不是document tree,而是根據document tree產生的render tree,而盒子模型就是render tree的節點。
* 注意:
* 1. CSS作用的是盒子(Box), 而不是元素(Element);
* 2. JS無法直接操作盒子。
盒子模型的結構
由於塊級盒子在驗證效果時幹擾資訊更少,便於理解盒子模型,因此下面將以塊級盒子模型來講解。
注意: 行級盒子模型與塊級盒子模型結構一致,只是行級盒子在此基礎上有自身特性而已。
從上面兩幅圖說明盒子模型其實就是由以下4個盒子組成:
1. content box:必備,由content area和4條content/inner edge組成;
2. padding box:可選,由padding和4條padding edge組成。若padding寬度設定為0,則padding edge與content edage重疊;
3. border box:可選,由border和4條border edge組成。若border寬度設定為0,則border edge與padding edage重疊;
4. margin box:可選,由margin和4條margin/outer edge組成。若margin寬度設定為0,則margin edge與border edage重疊。
對於剛接觸CSS的同學,經常會將"通過width/height屬性設定div元素的寬/高"掛在口邊,其實這句話是有誤的。
1. 首先css屬性width和height作用於div元素所產生的盒子,而不是元素本身;
2. 另外盒子模型由4個盒子組成,那width和height到底是作用於哪些盒子呢。
這裡就分為IE盒子模型和標準盒子模型了。
IE box model
IE5.5(怪異模式)採用IE盒子模型,其它將使用W3C標準盒子模型。
width = content-width + padding-width + border-widthheight = content-height + padding-height + border-height
Standard box model
width = content-widthheight = content-height
遊走於IE box model 和 Standard box model間的通道——box-sizing屬性
我們看到存在兩種width/height的劃分方式,到底哪種才對呢。其實兩種都對,具體看如何使用而已。另外IE8開始支援CSS3屬性box-sizing,讓我們可以自由選擇採用哪種盒子:)
box-sizing:content-box/border-box/inherit
content-box——預設值,採用Standard box model
border-box——採用IE box model
inherit——繼承父元素屬性值
sample:
Element{ -moz-box-sizing: border-box; // FireFox3.5+ -o-box-sizing: border-box; // Opera9.6(Presto核心) -webkit-box-sizing: border-box; // Safari3.2+ -ms-box-sizing: border-box; // IE8 box-sizing: border-box; // IE9+,Chrome10.0+,Safari5.1+,Opera10.6}
行級盒子——懷疑人生de起點:)
之前我理解的盒子模型如上所述,當我看到行級盒子的種種現象時,便開始懷疑人生了:(
width/height不起作用。。。
.defined-wh{ width: 100px; height: 50px; border: solid 1px red; background: yellow;}
對於block-level box
<div class="defined-wh"></div>
對於inline-level box
<span class="defined-wh"></span>
行級盒子的寬度怎麼會是0呢。高度是有的但不是50px啊,到底什麼回事啊。
原因很簡單,那就是行級盒子的content box的高/寬根本就不是通過height/width來設定的。
content box/area的高由font-size決定的;
content box/area的寬等於其子行級盒子的外寬度(margin+border+padding+content width)之和。
行級盒子被擠斷了。。。
.broken{ border: solid 1px red; background: yellow;}
對於block-level box
<div class="broken">一段文字一段文字一段文字一段文字一段文字一段文字</div>
對於inline-level box
<span class="broken">一段文字一段文字一段文字一段文字一段文字一段文字</span>
行級盒子被五馬分屍了,可憐兮兮的。更可憐的是我理解不了。。。
其實W3C Recommendation有說明的哦。
>The box model for inline elements in bidirectional context
>When the element's 'direction' property is 'ltr', the left-most generated box of the first line box in which the element appears has the left margin, left border and left padding, and the right-most generated box of the last line box in which the element appears has the right padding, right border and right margin.
>When the element's 'direction' property is 'rtl', the right-most generated box of the first line box in which the element appears has the right padding, right border and right margin, and the left-most generated box of the last line box in which the element appears has the left margin, left border and left padding.
就是說當inline-level box寬度大於父容器寬度時會被拆分成多個inline-level box,
當屬性direction為ltr時,margin/border/padding-left將作用於第一個的inline-level box,margin/border/padding-right將作用於最後一個的inline-level box;若屬性direction為rtl時,margin/border/padding-right將作用於第一個的inline-level box,margin/border/padding-left將作用於最後一個的inline-level box。
看到了沒。行級盒子真的會被分屍的,好殘忍哦:|
行級盒子怎麼不佔空間了。怎麼刷存在感啊。。。
.existed{ margin: 20px; padding: 20px; border: solid 1px red; background: yellow; background-clip: content-box;}
對於block-level box
<div>before bababababababa</div><div class="existed">babababababababababa</div><div>after bababababababa</div>
對於inline-level box
<div>before bababababababa</div><span class="existed">babababababababababa</span><div>after bababababababa</div>
看,行級盒子的margin/border/padding-top/bottom怎麼均不佔空間的。難道行級盒子僅有content box占空間嗎。
這裡已經涉及到水平和垂直方向排版的範疇了,僅以盒子模型已無法解析理解上述的問題。
(要結合https://www.w3.org/TR/CSS2/box.html和https://www.w3.org/TR/CSS21/visuren.html、https://www.w3.org/TR/CSS21/visudet.html來理解了。)
在深入解釋inline-level box的上述現象前,我們需要補充一下:
1. 一個元素會對應0~N個box;(當設定`display:none;`時,則對應0個box)
2. 根據`display`屬性值,元素會對應不同類型的controlling box(inline/block-level box均是controlling box的子類). 就CSS2而言`display:inline|inline-block|inline-table|table-cell|table-column-group`的元素對應inline-level box,而`display:block|list-item|table|table-caption|table-header-group|table-row|table-row-group|table-footer-