深入理解CSS盒子模型
盒模型
盒模型是CSS的基石之一,它指定元素如何顯示以及(在某種程度上)如何交互。頁面上每一個元素都被看做一個矩形框,框由元素的內容,內邊距 (padding),邊框 (border)和外邊距 (margin)組成,如下圖所示。
內邊距出現在內容區域周圍,若給元素上添加背景,背景將會應用於由內容和內邊距組成的區域。添加邊框,會在內邊距的區域外加一條線,這些線有多種樣式,後面會有所介紹。在邊框外邊是外邊距,外邊距是透明的,一般使用它控制元素之間的間隔。
CSS2.1還包含outline屬性,繪製在元素框之上,不影響元素的大小或定位。大多數現代瀏覽器(包括IE8)都支援outline,但IE7和更低版本不支援。
內邊距、邊框、外邊距都是可選的,默認值為零。但許多元素將由用戶代理樣式表設置外邊距和內邊距,所以將元素的margin和padding設置為零,對寫整個樣式有幫助,這項工作一般由全局reset進行。
1. IE和盒模型
IE的早期版本,包括IE6,在混雜模式中使用自己的非標準盒模型。瀏覽器的width屬性不是內容的寬度,而是內容,內邊距和邊框的總和。添加的內邊距越多,給內容預留的空間就越少。
在CSS3中,可通過box-sizing屬性定義使用哪種盒模型,但除了一些非常特殊的場合很少使用該屬性。
目前最好的解決方案是迴避這個問題。也就是,不給元素添加指定寬度的內邊距,而是嘗試將內邊距或外邊距添加到父元素或子元素。
2. box-sizing
box-sizing屬於CSS3內容,屬性值包括:content-box, border-box, inherit。該屬性用於更改預設的CSS盒模型寬度和高度的計算方式,可使用該屬性模擬不正確支援CSS盒模型規範的瀏覽器行為。
- content-box
- 根據CSS標準的起始值和預設值(標準盒模型,現在瀏覽器默認支援該屬性)。width和height只包括內容本身的寬度和高度。元素框的大小=width/height+padding+border+margin
- border-box
- 該屬性值下,width和height屬性包括內容(content),內邊距(padding)和邊框(border)。
- inherit。指定 box-sizing 屬性的值,應該從父元素繼承
瀏覽器支援:IE8及以上,Chrome 10.0以上,FireFox 29.0 以上,Safari 5.1以上,Opera 9.5以上。
示例:
div {
box-sizing:border-box;
-moz-box-sizing:border-box; /* Firefox */
-webkit-box-sizing:border-box; /* Opera */
width:50%;
float:left;
}
3. margin
margin屬性用於設置外邊距,下面我們將講述margin一些比較有意思的知識點
3.1 margin與容器尺寸
在標準盒模型中,border-box部分,即包括border,padding,content的方框代表可視尺寸(clientWidth)。外邊距加上可視尺寸則是「佔據尺寸」(張鑫旭大神自命名)。
在一些前提下,通過設置margin屬性可以改變可視尺寸和「佔據尺寸「的大小。
1. margin改變可視尺寸
適用範圍:
-
適用於沒有設定width/height的普通block水平元素(
float,absolute/fixed,inline水平,table cell元素。..) -
只適用於水平方向尺寸
可利用該特性實現一側定寬自適應布局和兩端對齊布局效果。
2. margin改變」佔據尺寸「
適用範圍:
-
block/inline-block水平元素均適用
-
與有無設定width/height值無關
-
適用於水平方向和垂直方向
可利用該效果實現滾動容器上下留白及等高布局效果。
3.2 margin與百分比單位
-
普通元素的百分比margin都是相對於容器(父級元素)的寬度計算。
-
絕對定位元素的百分比margin都是相對於第一個定義祖先元素(relative/absolute/fixed)的計算寬度
- 在IE中,絕對定位元素的百分比margin是相對於第一個定義祖先元素的寬度計算
- 在Chrome/FireFox/Opera中,絕對定位元素的百分比margin是相對於第一個定義祖先元素的border-box的寬度計算的。Opera瀏覽器由於作者是windows系統,安裝的windows版本,感覺表現得很奇怪。沒有顯示出數值,不方便得出結論,希望有讀者能夠測試了在評論區反映一下,共同探討之,謝謝!
3.3 margin重疊
margin重疊,即外邊距疊加,是一個比較簡單的概念。但是,在實踐中對網頁進行布局時,它會造成很多混淆。簡單地說,當兩個或更多垂直外邊距相遇時,它們將形成一個外邊距。這個外邊距的高度等於兩個發生重疊的外邊距的高度中的較大值。
1.3. 1 margin重疊特性
- 只有普通文檔流中的塊框的垂直外邊距才會發生外邊距疊加(不包括float框和absolute框以及行內框)
- 不考慮writing-mode,只發生在垂直方向(margin-top/margin-bottom)
1.3.2 margin重疊的3種情境
margin重疊3種情境:
- 相鄰的兄弟元素
- 父級和第一個/最後一個子元素
- margin-top重疊其他條件
- 父元素非塊狀格式化上下文元素
- 父元素沒有border-top/padding-top設置
- 父元素和第一個子元素之間沒有inline元素分隔
- margin-bottom重疊其他條件
- 父元素非塊狀格式化上下文元素
- 父元素沒有border-bottom/padding-bottom值
- 父元素和最後一個子元素之間沒有inline元素分隔
- 父元素沒有height,min-height限制
- 幹掉margin-top重疊
- 在父元素加屬性,overflow:hidden;
- 父元素設置border-top/padding-top值
- 父元素與第一個子元素之間插入inline元素,如空格
- 幹掉margin-bottom重疊
- 在父元素加屬性,overflow:hidden;
- 父元素設置border-bottom/padding-bottom值
- 設置height相關聲明(min-height以及height。max-height不起作用)
- margin-top重疊其他條件
- 空的block元素(自己的上下外邊距疊加)
- 重疊其他條件
- 元素不能有border/padding值
- 裡面沒有inline元素
- 沒有height,或者min-height
- 重疊其他條件
1.3.3 margin重疊計算規則
- 正正取大值
- 正負值相加
- 負負最負值
1.3.4 margin重疊的意義
- 連續段落或列表之類,如果沒有margin重疊,首尾項間距會和其他兄弟標籤1:2關係,排版不自然
- web種任何地方嵌套或直接放入任何裸div,都不會影響原來的布局
- 遺落的空任意多個p元素,不會影響原來的閱讀排版
1.4 margin auto
作用機制:自動填充元素佔據空間的剩餘空間,可利用其實現水平居中:
div{
width:300px;
margin:0 auto;
}
注意:margin實現居中,必須計算後的距離不能是負值。
margin 如何實現垂直布局?
- 改變流(但水品不再居中)
.father{height:200px; width:100%; writing-mode:vertical-lr;}
.son {height:100px; width:500px; margin:auto;}
2.絕對元素的margin:auto居中(IE8+)
.father{ height:200px; position:relative;}
.son{ position:absolute; top:0; right: 0; bottom:0; left:0;
width:500px; height:100px; margin:auto;}
1.6 CSS margin失效情形
1.inline水平元素的垂直margin無效
前提:
- 非替換元素(如img)
- 正常書寫模式
2.margin重疊
3.display:table-cell與margin
margin可應用於所有元素,除了diplay為table相關類型(不包括table-caption,table以及inline-table)的所有。甚至可應用於::first-letter
4.絕對定位元素非定位方向的margin值「無效」
絕對定位元素的margin值一直有效,但由於設置了絕對定位,脫離了文檔流,所以看不出效果。
5.鞭長莫及導致margin無效,一些情況下,如浮動時,margin無效可能是不夠大。
6.內聯特性導致margin無效,例如對於圖片,使用margin的負值定位,不會出現在容器之外。
1.7 了解margin-start/margin-end屬性
Chrome/FireFox目前支援該屬性,IE不支援
margin-start
- 正常流向margin-start與margin-left等效,兩者重疊不累加。
- 如果水平流是從右往左,margin-start等同於margin-right;
- 在垂直流下(writing-mode:vertical-*),margin-start等同於margin-top;
margin-end
- 正常流向margin-end與margin-right等效,兩者重疊不累加。
- 如果水平流是從右往左,margin-end等同於margin-left;
- 在垂直流下(writing-mode:vertical-*),margin-end等同於margin-bottom;
4. border
4.1 border-width 不支援百分比
盒子模型種,padding,margin都支援百分比,但是border,即邊框寬度不支援百分比;來自張鑫旭大神的理解:border-width不支援百分比是由於其語義限制,因為可以看到平板和手機兩個不同顯示大小的邊框大小並不根據元素長寬變化而變化。
4.2 了解各種border-style類型
-
solid (實線)
-
dashed (虛線)
在Chrome/FireFox中,虛線邊框的寬高為3:1,IE為2:1。
-
dotted(點線)
在Chrome/FireFox中,點的形狀為方形,IE為圓形。
-
double(雙實線)
雙線寬度相等,中間空白間隔$\pm$1
-
inset(內凹)
4.3 border-color與color
border-color默認繼承自color,即未指定color時border-color與color一樣。類似的還有box-shadow,text-shadow,outline。
5. padding
5.1 padding與容器尺寸
當width auto或者box-sizing為border-box,但是padding大小超過寬高時,padding會影響元素尺寸。
對於block元素:
- padding值暴走,一定會影響尺寸
- width非auto,padding影響尺寸
- witdh為auto或box-sizing為border-box時,同時padding值未暴走,不影響元素尺寸。
對於內聯元素:
水平padding影響尺寸,垂直padding不影響尺寸。但會影響背景色。
5.2 padding負值與百分比值
padding不支援任何負值,padding的百分比相對於寬度計算。
inline元素的百分比值
- 同樣相對於寬度計算
- padding會斷行
- 默認的高度寬度細節差異
空inline元素+padding高端也不等。是由於inline元素的垂直padding會讓”幽靈空白節點”顯現,也就是規範中的「strut」出現。這時通過設置font-size:0規避
span{padding:50%;font-size:0;}
5.3 標籤元素內置padding
button表單按鈕設置padding:0,Chrome是ok的,但是在FireFox中左右依然會有padding,通過設置屬性-moz-focus-inner規避;IE瀏覽器中,IE7文字越多左右padding逐漸變大,通過overflow屬性設置規避。
button::-moz-focus-inner {
padding:0;
}
button{padding:0;overflow:visible;}
對於button,padding與高度計算不兼容,所以一般通過label標籤實現button,而button通過絕對定位到頁面之外或者z-index隱藏在頁面下方。
<button id="btn"></button>
<label for="btn">按鈕</label>
label{
display:inline-block;
line-height:20px;
padding:10px;
}