這是寒冬大神提出的一個題目,剛開始看到這題的時候完全不知道從什么地方回答起好,題目內容比較廣泛,找不到針對點。后來我覺得這個題目應該能拆成幾個點來回答:1、'display'、'position' 和 'float' 的相互關系;2、position跟display、overflow、float下的margin collapse。
那么這三種布局和框形成的關鍵特性( display )之間有什么關系呢,請看下面流程圖:
轉換對應表:
設定值 | 計算值 |
---|---|
inline-table | table |
inline, run-in, table-row-group, table-column, table-column-group, table-header-group, table-footer-group, table-row, table-cell, table-caption, inline-block |
block |
其他 | 同設定值 |
總的來說,可以把它看作是一個類似優先級的機制, "position:absolute" 和 "position:fixed" 優先級最高,有它存在的時候,浮動不起作用,'display' 的值也需要調整; 其次,元素的 'float' 特性的值不是 "none" 的時候或者它是根元素的時候,調整 'display' 的值; 最后,非根元素,並且非浮動元素,並且非絕對定位的元素,'display' 特性值同設置值。
這從另一個側面說明了一個問題:浮動或絕對定位的元素,只能是塊元素或表格。
1. 'display' 的值為 'none'
如果 'display' 的值為 'none',那么 'position' 和 'float' 不起作用。在這種情況下,元素不產生框。因此浮動和定位無效。
2. 'position' 的值是 'absolute' 或 'fixed'
否則,如果 'position' 的值是 'absolute' 或 'fixed',框就是絕對定位的,'float' 計算后的值應該是 'none',並且,'display' 會被按照上表設置。 框的位置將由 'top','right','bottom' 和 'left' 屬性和該框的包含塊確定。
也就是說,當元素是絕對定位時,浮動失效,'display' 會被按規則重置。
示例代碼:
<script type="text/javascript"> function getStyle(obj, style) { var _style = (style == "float") ? "styleFloat" : style; return document.defaultView ? document.defaultView.getComputedStyle(obj, null).getPropertyValue(style) : obj.currentStyle[_style.replace(/-[a-z]/g, function() { return arguments[0].charAt(1).toUpperCase(); })]; } window.onload = function() { document.getElementById("info").innerHTML = "float : " + getStyle(document.getElementById("test"), "float") + "<br/>display : " + getStyle(document.getElementById("test"), "display"); } </script> <div id="test" style="position:absolute; float:left;display:inline;"></div> <div id="info"></div>
上面代碼中有一個既是絕對定位又是浮動的元素,以上代碼可取出其 'display' 和 'float' 的計算值。
IE 中,'float' 值和 'display' 的特性值未發生變化,還是 "float: left; display: inline"。
其他瀏覽器中計算后的結果是:"float: none; display: block"。
3. 'float' 的值不是 "none"
如果 'float' 的值不是 "none",該框浮動並且 'display' 會被按照轉換對應表設置。
<!DOCTYPE html> <script type="text/javascript"> function getStyle(obj, style) { var _style = (style == "float") ? "styleFloat" : style; return document.defaultView ? document.defaultView.getComputedStyle(obj, null).getPropertyValue(style) : obj.currentStyle[_style.replace(/-[a-z]/g, function() { return arguments[0].charAt(1).toUpperCase(); })]; } window.onload = function() { document.getElementById("info").innerHTML = "display : " + getStyle(document.getElementById("test"), "display"); } </script> <span id="test" style="width:100px; height:100px; border:1px solid red;float:left;">float span</span> <div id="info"></div>
按照規則,SPAN 是行內元素,因此不能夠設置其寬度和高度。但是浮動后,'display' 值按照轉換對應表設置后,成為塊級元素。
IE 中截圖:
其他瀏覽器中:
4. 元素是根元素
如果元素是根元素,'display' 的值按照轉換對應表設置。
5. 否則,應用指定的 'display' 特性值。
二、position跟display、overflow、float下的margin collapse。margin collapse我覺得這里的意思應該是Collapsing margins,即外邊距折疊,指的是毗鄰的兩個或多個外邊距 (margin) 會合並成一個外邊距。
其中所說的 margin 毗鄰,可以歸結為以下兩點:
- 這兩個或多個外邊距沒有被非空內容、padding、border 或 clear 分隔開。
- 這些 margin 都處於普通流中。
1.兩個或多個毗鄰的普通流中的塊元素垂直方向上的 margin 會折疊。
注意一點,在沒有被分隔開的情況下,一個元素的 margin-top 會和它普通流中的第一個子元素(非浮動元素等)的 margin-top 相鄰; 只有在一個元素的 height 是 "auto" 的情況下,它的 margin-bottom 才會和它普通流中的最后一個子元素(非浮動元素等)的 margin-bottom 相鄰。
示例代碼:
<div style="border:1px solid red; width:100px;"> <div style="margin:50px 0; background-color:green; height:50px; width:50px;"> <div style="margin:20px 0;"> <div style="margin:100px 0;">B</div> </div> </div> </div>
效果圖:
以上代碼中,margin 會把 B 的包含塊撐開。
如果一個元素的 height 特性的值不是 auto,那么它的 margin-bottom 和它子元素的 margin-bottom 不算相鄰,因此,不會發生折疊。 margin-top 沒有此限制,所以是 100px,margin-bottom 沒有折疊,只有 50px。
垂直方向
是指具體的方位,只有垂直方向的 margin 才會折疊,也就是說,水平方向的 margin 不會發生折疊的現象。
折疊后 margin 的計算
1). 參與折疊的 margin 都是正值
例子:
<div style="height:50px; margin-bottom:50px;width:50px; background-color: red;">A</div> <div style="height:50px;margin-top:100px; width:50px; background-color: green;">B</div>
示意圖:
在 margin 都是正數的情況下,取其中 margin 較大的值為最終 margin 值。
2). 參與折疊的 margin 都是負值
當 margin 都是負值的時候,取的是其中絕對值較大的,然后,從 0 位置,負向位移。
示例代碼:
<div style="height:100px; margin-bottom:-75px;width:100px; background-color: red;">A</div> <div style="height:100px;margin-top:-50px; margin-left:50px; width:100px; background-color: green;">B</div>
示意圖:
3). 參與折疊的 margin 中有正值,有負值
如果,毗鄰的 margin 中有正值,同時存在負值會怎樣呢?有正有負,先取出負 margin 中絕對值中最大的,然后,和正 margin 值中最大的 margin 相加。
示例代碼:
<div style="height:50px; margin-bottom:-50px;width:50px; background-color: red;">A</div> <div style="height:50px;margin-top:100px; width:50px; background-color: green;">B</div>
示意圖:
上面的例子最終的 margin 應該是 100 + (-50) = 50px。
4). 相鄰的 margin 要一起參與計算,不得分步計算
要注意,相鄰的元素不一定非要是兄弟節點,父子節點也可以,即使不是兄弟父子節點也可以相鄰。
而且,在計算時,相鄰的 margin 要一起參與計算,不得分步計算。
一個復雜的實例:
<div style="margin:50px 0;background-color:green; width:50px;"> <div style="margin:-60px 0;"> <div style="margin:150px 0;">A</div> </div> </div> <div style="margin:-100px 0;background-color:green; width:50px;"> <div style="margin:-120px 0;> <div style="margin:200px 0;">B</div> </div> </div>
錯誤的計算方式:算 A 和 B 之間的 margin,分別算 A 和其父元素的折疊,然后與其父元素的父元素的折疊,這個值算出來之后,應該是 90px。依此法算出 B 的為 80px;然后,A和B折疊,margin 為 90px。
請注意,多個 margin 相鄰折疊成一個 margin,所以計算的時候,應該取所有相關的值一起計算,而不能分開分步來算。
以上例子中,A 和 B 之間的 margin 折疊產生的 margin,是6個相鄰 margin 折疊的結果。將其 margin 值分為兩組:
- 正值:50px,150px,200px
- 負值:-60px,-100px,-120px
根據有正有負時的計算規則,正值的最大值為 200px,負值中絕對值最大的是 -120px,所以,最終折疊后的 margin 應該是 200 + (-120) = 80px。
2.浮動元素、inline-block 元素、絕對定位元素的 margin 不會和垂直方向上其他元素的 margin 折疊
浮動元素的 margin 在垂直方向上也不會發生 margin 折疊,即使和它相鄰的子元素也不會。
<div style="margin-bottom:50px;width:50px; height:50px; background-color:green;">A</div> <div style="margin-top:50px; width:100px; height:100px; background-color:green; float:left;"> <div style="margin-top:50px;background-color:gold;">B</div> </div>
示意圖:
兩個綠色的塊兒之間,相距100px,而若 B 和它的浮動包含塊發生 margin 折疊的話,金色的條應該位於綠色塊的最上方,顯然,沒有發生折疊。inline-block 元素、絕對定位元素的 margin同樣如此, 不會和垂直方向上其他元素的 margin 折疊。
3.創建了塊級格式化上下文的元素,不和它的子元素發生 margin 折疊
以 “overflow : hidden” 的元素為例:
<div style="margin-top:50px; width:100px; height:100px; background-color:green; overflow:hidden;"> <div style="margin-top:50px; background-color:gold;">B</div> </div>
若 B 和它的 "overflow:hidden" 包含塊發生 margin 折疊的話,金色的條應該位於綠色塊的最上方,否則,沒有發生。
示意圖:
4.元素自身的 margin-bottom 和 margin-top 相鄰時也會折疊
自身 margin-bottom 和 margin-top 相鄰,只能是自身內容為空,垂直方向上 border、padding 為 0。
示例:
<div style="border:1px solid red; width:100px;"> <div style="margin-top: 100px;margin-bottom: 50px;></div> </div>
以上代碼運行后,我們講得到的是紅色邊框的正方形,方框的寬高都應該是 100px,高度不應該是 150px。
示意圖: