最近在學習flex布局,在贊嘆其便捷性的同時,回想起之前使用css2的時候實現等高或者等寬布局的麻煩。同時也看到[The Definitive Guide to Using Negative Margins這篇文章對于負邊距的介紹,這里參考并總結一二,加深理解。
我們在平時的開發中很少使用負邊距,不過其實可以解決很多問題。首先,W3C標準并不反對使用負邊距,此外,使用負邊距時并不會時節點脫離文檔流,因此能夠影響后繼節點的布局,此外,它也有著較好的兼容性,在適當的時候合適的使用它可能解決大問題。
我們先借用參考文章里的一張圖來回顧一下盒模型:
仔細看圖中的箭頭所示,對一個非float元素來說,top,left屬性影響元素本身的定位,而right,bottom影響的是后繼元素的定位。理解這點其實很重要,很多時候我們會覺得很奇怪,明明設置了margin-bottom為0,可是為什么沒有相對父元素居于底部呢。
一個有趣的現象是,當我們并未對節點設置寬度,但是設置了負的margin-left或者margin-right時,會導致節點變寬,其效果有點類似padding。
而對于float節點,負的margin稍顯復雜,我們不妨先看看float方向和負邊距方向相反的情形:
#mydiv1 {
float:left;
margin-right:-100px;
}
而HTML結構為
<div id="mydiv1">First</div>
<div id="mydiv2">Second</div>
我們使用codepen來查看上述結果,不難發現,mydiv2由于負值margin-right的重疊作用,直接覆蓋mydiv1.當我們把mydiv1設置成寬度100%時,便輕松實現了mydiv2固定寬度,而mydiv1占寬100%的布局,而不需使用position:absolute.
當mydiv1和mydiv2都被設置了margin-right為-20px時,其效果是mydiv1的寬度減少了20px,因為被mydiv2覆蓋的緣故。
不難想象,當mydiv1的負margin-right設置的值超過其寬度時,則完全被覆蓋。
這里可以思考一下,假設頁面布局如下:
<div id="mydiv">Start</div>
<div id="mydiv1">First</div>
<div id="mydiv2">Second</div>
而樣式如下:
#mydiv {
float: left;
}
#mydiv1 {
float:left;
margin-right:-200px;
}
#mydiv2 {
float: left;
margin-right: -20px;
}
那么mydiv2會否覆蓋到mydiv呢?
再看一個例子,要把單列的列表改成多列混排,繼續盜圖:
HTML如下:
<ul>
<li class="col1">Eggs</li>
<li class="col1">Ham<li>
<li class="col2 top">Bread<li>
<li class="col2">Butter<li>
<li class="col3 top">Flour<li>
<li class="col3">Cream</li>
</ul>
CSS如下:
ul {list-style:none;}
li {line-height:1.3em;}
.col2 {margin-left:100px;}
.col3 {margin-left:200px;}
.top {margin-top:-2.6em;} /* the clincher */
如此,便順利的從單列布局轉為多列布局。初看這部分代碼時,我也覺得很奇怪,怎么第4個和第6個li標簽無需設置margin-top就可以實現節點上移而實現多個塊元素相互重疊的效果?這里必須提到的一點是,負值的margin-top會導致文檔流上移,想明白了這一點,就不難理解這里的布局為何是這樣了。關于margin的更深入的討論,我會在參考文獻中列出。
負值的margin還有其他應用,比如氣泡文字,文本疊加效果等,再也不用使用死板的絕對定位了。
當然,要實現多列布局也很easy:
HTML
<div id="content"> <p>Main content in here</p> </div>
<div id="sidebar"> <p>I’m the Sidebar! </p> </div>
CSS
#content {width:100%; float:left; margin-right:-200px;}
#sidebar {width:200px; float:left;}
#content p {margin-right:210px;}
這里給p設置margin-right很重要,因為content的實際寬度仍然是100%,否則會導致p標簽和sidebar重疊。
使用負的margin-top可能會導致一系列問題,比如選擇和點擊頁面元素,由于節點相互重疊可能導致層級不符合預期,解決方法也很簡單,使用position:relative即可!
最后,再回顧一下經典的等高布局代碼:
CSS
.div {
width: 100px;
overflow: hidden;
}
.div1, .div2 {
padding-bottom: 200px;
margin-bottom: -200px;
float: left;
width: 50%;
word-wrap: break-word;
}
HTML
<div class="div">
<div class="div1">111111111111111111111111111</div>
<div class="div2">
22222222222sd豆腐干豆腐豆腐干豆腐干豆腐干豆腐
</div>
</div>
這里主要用到的原理是:
- 未設置父節點高度時,其高度由高度最高的子節點高度決定
- 負值的margin-bottom可以減少父節點高度,對子節點高度不影響,也不影響子節點定位
關于margin,其實還有很多值得去深挖的東西,比如當沒有設置padding和border時,子節點和父節點的margin-to會重疊;而兩個平級的節點之間的margin-bottom和margin-top之間也會重疊,在你不知道的CSS——BFC(塊級格式化上下文)中,我們會對此進行詳細解釋。
參考文獻:
你不知道的CSS——BFC(塊級格式化上下文)
The Definitive Guide to Using Negative Margins
Html+CSS__margin 負值之美:負margin在頁面布局中的應用
深入理解margin重疊以及負margin對元素大小的影響
不要告訴我你懂margin
由淺入深漫談margin屬性