一、margin可以为负值
在盒模型中,内容区的width/height、padding、border都不能为负值,但是margin例外,它可以为负值。
margin负值的本质,在于它改变了元素在普通流中所占据的空间。
关于margin负值的使用技巧,了解不多,日后有机会再补充,此处先贴三个经典应用。
1. margin-left负值结合浮动实现不改变DOM结构的流体布局。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>不改变DOM结构的流体布局</title> 6 <style> 7 .container { 8 width:700px; 9 margin: 50px auto; 10 background-color: orange; 11 font-size: 16px; 12 line-height: 1.5; 13 } 14 15 .box1 { 16 width:100%; 17 float:left; 18 } 19 20 img { 21 float: left; 22 margin-left: -200px; 23 } 24 25 .box2 { 26 margin-right: 230px; 27 } 28 29 .clearfix:after { 30 content: ""; 31 display: table; 32 clear: both; 33 } 34 35 .clearfix { 36 *zoom: 1; 37 } 38 39 h3,p { 40 padding-left: 10px; 41 } 42 43 </style> 44 </head> 45 <body> 46 <div class="container clearfix"> 47 <div class="box1"> 48 <div class="box2"> 49 <h3>不改变DOM位置的流体布局</h3> 50 <p>假如有一段文本和一幅图像,在DOM节点中,文本在前,图像在后,怎么能把图像定位到右边呢?</p> 51 <p>通常的做法是,调换DOM节点中图像与文本的位置,让图像在前,文本在后,然后将图像浮动到右边即可。</p> 52 <p>但这样改变DOM节点顺序始终不妥,还有什么更好的方法呢?</p> 53 <p>下面就介绍一种新的思路来完成布局。</p> 54 <ul> 55 <li>将文本用div包起来,定义为box1;现在的结构是一个box1和一个img。</li> 56 <li>将box1宽度设为100%,左浮动;将img设置一个宽度,也左浮动,然后margin-left设为负的宽度值;此时图像就定位到文本的右边啦。 57 (或者,将box1的宽度设为100%,左浮动,并且margin-right为负的图像宽度;图像也会定位到文本右边。)</li> 58 <li>但是有一个问题,图像盖住了文本内容,这可怎么办?</li> 59 <li>重点来了,在box1中增加一个box2,box2把文本全部包起来,然后margin-right设为图像的宽度(+额外的间距),这样就解决问题啦!</li> 60 </ul> 61 </div><!--关闭box2--> 62 </div><!--关闭box1--> 63 <img src="http://imgsrc.baidu.com/forum/w%3D580/sign=0c101fe665380cd7e61ea2e59145ad14/f9a3492762d0f7032de1758a08fa513d2797c542.jpg" alt="a picture" style="200px;height:300px" /> 64 </div><!--关闭container--> 65 </body> 66 </html>
2. margin负值实现两列等高布局
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>margin负值实现等高布局</title> 6 <style> 7 div.container { 8 margin-left: 200px; 9 overflow: hidden; 10 } 11 12 div.box { 13 width:300px; 14 float: left; 15 margin-right: 20px; 16 } 17 18 div.box1 { 19 background-color: brown; 20 margin-bottom: -9999px; 21 padding-bottom: 9999px; 22 } 23 24 div.box2 { 25 background-color: green; 26 margin-bottom: -9999px; 27 padding-bottom: 9999px; 28 } 29 30 p { 31 margin-bottom: 50px; 32 } 33 34 </style> 35 </head> 36 <body> 37 <div class="container"> 38 <div class="box box1"> 39 <p>box1</p> 40 <p>box1</p> 41 </div> 42 <div class="box box2"> 43 <p>box2</p> 44 <p>box2</p> 45 <p>box2</p> 46 <p>box2</p> 47 <p>box2</p> 48 <p>box2</p> 49 <p>box2</p> 50 <p>box2</p> 51 </div> 52 <div class="container"> 53 </body> 54 </html>
其实现原理为margin负值与padding正值相互抵消。
3.margin负值实现列表两端对齐
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>margin负值清除列表右边距</title> 6 <style> 7 * { 8 margin: 0; 9 padding: 0; 10 } 11 12 .box { 13 width:540px; 14 background-color: orange; 15 margin:50px auto; 16 } 17 18 .box2 ul,.box3 ul { 19 float: left; 20 background-color: purple; 21 margin-right: -10px; 22 } 23 24 li { 25 float: left; 26 list-style: none; 27 margin-right: 10px; 28 } 29 30 p { 31 font-size: 16px; 32 line-height: 1.5; 33 padding :5px 15px 5px 20px; 34 } 35 36 p.clear { 37 clear: both; 38 } 39 40 .box3 { 41 overflow: hidden; 42 } 43 44 .box3 ul { 45 line-height: 0; 46 } 47 48 </style> 49 </head> 50 51 <body> 52 <div class="box box1"> 53 <ul> 54 <li><img src="http://imgsrc.baidu.com/forum/w%3D580/sign=0c101fe665380cd7e61ea2e59145ad14/f9a3492762d0f7032de1758a08fa513d2797c542.jpg" alt="A picture" style="100px;height:150px" /></li> 55 <li><img src="http://imgsrc.baidu.com/forum/w%3D580/sign=0c101fe665380cd7e61ea2e59145ad14/f9a3492762d0f7032de1758a08fa513d2797c542.jpg" alt="A picture" style="100px;height:150px" /></li> 56 <li><img src="http://imgsrc.baidu.com/forum/w%3D580/sign=0c101fe665380cd7e61ea2e59145ad14/f9a3492762d0f7032de1758a08fa513d2797c542.jpg" alt="A picture" style="100px;height:150px" /></li> 57 <li><img src="http://imgsrc.baidu.com/forum/w%3D580/sign=0c101fe665380cd7e61ea2e59145ad14/f9a3492762d0f7032de1758a08fa513d2797c542.jpg" alt="A picture" style="100px;height:150px" /></li> 58 <li><img src="http://imgsrc.baidu.com/forum/w%3D580/sign=0c101fe665380cd7e61ea2e59145ad14/f9a3492762d0f7032de1758a08fa513d2797c542.jpg" alt="A picture" style="100px;height:150px" /></li> 59 </ul> 60 <p class="clear">每个图像的宽度为100px,右外边距为10px,为了达到两端对齐的效果,容器的宽度需要540px。</p> 61 <p>但是当我们看页面效果的时候,会发现最后一张图像到了第二行。</p> 62 <p>究其原因,是因为第一行所剩余的宽度只剩下100px,而图像需要100px+10px的距离,所以被逼无奈只能到下一行。</p> 63 </div> 64 <div class="box box2"> 65 <ul> 66 <li><img src="http://imgsrc.baidu.com/forum/w%3D580/sign=0c101fe665380cd7e61ea2e59145ad14/f9a3492762d0f7032de1758a08fa513d2797c542.jpg" alt="A picture" style="100px;height:150px" /></li> 67 <li><img src="http://imgsrc.baidu.com/forum/w%3D580/sign=0c101fe665380cd7e61ea2e59145ad14/f9a3492762d0f7032de1758a08fa513d2797c542.jpg" alt="A picture" style="100px;height:150px" /></li> 68 <li><img src="http://imgsrc.baidu.com/forum/w%3D580/sign=0c101fe665380cd7e61ea2e59145ad14/f9a3492762d0f7032de1758a08fa513d2797c542.jpg" alt="A picture" style="100px;height:150px" /></li> 69 <li><img src="http://imgsrc.baidu.com/forum/w%3D580/sign=0c101fe665380cd7e61ea2e59145ad14/f9a3492762d0f7032de1758a08fa513d2797c542.jpg" alt="A picture" style="100px;height:150px" /></li> 70 <li><img src="http://imgsrc.baidu.com/forum/w%3D580/sign=0c101fe665380cd7e61ea2e59145ad14/f9a3492762d0f7032de1758a08fa513d2797c542.jpg" alt="A picture" style="100px;height:150px" /></li> 71 </ul> 72 <p class="clear">第一种办法是,给最后一张图像增加一个class,将它的margin-right设为0。</p> 73 <p>然而,margin才是本次的主角。</p> 74 <p>稍微分析一下,是因为第一行的水平距离少了10px,所以图像才会到第二行的;那么,如果给第一行的宽度加10px,图像是不是就应该上去呢?</p> 75 <p>那么,这个问题就变成了怎么给ul的宽度在右边加上10px,margin负值就可以实现这个效果。</p> 76 <p>于是,我们给ul添加margin-right,其值为-10px,得到这个结果。</p> 77 <p>为了看得清楚明白,给ul增加了背景色;很明显地看到,ul元素的右边增加了10px的宽度,图像算是两端对齐了,但是这个问题还没完。</p> 78 <p>最右边那多出去的10px和图像下边缘那一丢丢的多出来的东西,实在是太影响美观了,必须得处理一下。</p> 79 <p>后续。。。</p> 80 </div> 81 <div class="box box3"> 82 <ul> 83 <li><img src="http://imgsrc.baidu.com/forum/w%3D580/sign=0c101fe665380cd7e61ea2e59145ad14/f9a3492762d0f7032de1758a08fa513d2797c542.jpg" alt="A picture" style="100px;height:150px" /></li> 84 <li><img src="http://imgsrc.baidu.com/forum/w%3D580/sign=0c101fe665380cd7e61ea2e59145ad14/f9a3492762d0f7032de1758a08fa513d2797c542.jpg" alt="A picture" style="100px;height:150px" /></li> 85 <li><img src="http://imgsrc.baidu.com/forum/w%3D580/sign=0c101fe665380cd7e61ea2e59145ad14/f9a3492762d0f7032de1758a08fa513d2797c542.jpg" alt="A picture" style="100px;height:150px" /></li> 86 <li><img src="http://imgsrc.baidu.com/forum/w%3D580/sign=0c101fe665380cd7e61ea2e59145ad14/f9a3492762d0f7032de1758a08fa513d2797c542.jpg" alt="A picture" style="100px;height:150px" /></li> 87 <li><img src="http://imgsrc.baidu.com/forum/w%3D580/sign=0c101fe665380cd7e61ea2e59145ad14/f9a3492762d0f7032de1758a08fa513d2797c542.jpg" alt="A picture" style="100px;height:150px" /></li> 88 </ul> 89 <p class="clear">接上回。。。</p> 90 <p>对于右边冒出去的那10px,我们可以在ul元素的父元素div.box3增加一个overflow属性,其值为hidden,让多出去的部分隐藏。</p> 91 <p>对于图像下边多出来的那一点点背景颜色,实际上是line-height与vertical-align:baseline在联合作怪,将line-height设为0即可。</p> 92 </div> 93 </body> 94 </html>
此例中最后提到的清除图像下边缘背景颜色的方法,如有疑问,请点这里,CSS line-height与vertical-align:baseline。
关于margin负值实现列表两端对齐的原理,我在demo中已有相关陈述,个人理解如此,有错请拍砖。
关于margin负值能够让元素宽度增加,是因为元素的盒子宽度必须等于父元素的width。
此例中,div元素的width为540px,ul元素是块级元素,默认100%继承div的width,也就是540px,如果margin-right设为为-10px,那么width就必须增加10px,因为 -10+550=540。也就是说,margin负多少,width就必须增加多少,以保证盒子宽度与父元素的width相等。
但是有一个前提,width不能为定值。
height同理。
补充:
1. 受《CSS权威指南》启发,突发奇想
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>margin负值布局</title> 6 <style> 7 .container { 8 width: 500px; 9 height: 400px; 10 margin: 50px auto; 11 background-color: orange; 12 border: 3px solid #000; 13 } 14 15 .wraper { 16 width: 400px; 17 height: 300px; 18 margin: 30px auto; 19 background-color: cyan; 20 border: 3px solid #000; 21 } 22 23 p { 24 font-size: 16px; 25 line-height: 1.5; 26 padding: 5px 5px 5px 20px; 27 } 28 29 .para1 { 30 margin: 20px -3px 20px 25%; 31 background-color: orange; 32 border: 3px solid #000; 33 border-right: none; 34 } 35 36 .para2 { 37 text-align: right; 38 margin: 20px 25% 20px -3px; 39 background-color: orange; 40 border: 3px solid #000; 41 border-left: none; 42 } 43 44 </style> 45 </head> 46 47 <body> 48 <div class="container"> 49 <div class="wraper"> 50 <p>我是第一段。</p> 51 <p class="para1">我是第二段。</p> 52 <p>我是第三段。</p> 53 <p class="para2">谢谢观赏!</p> 54 </div> 55 </div> 56 </body> 57 </html>
效果是这样的:
作为第一个自创布局,我要把它发扬光大,嗯嗯。。。
补充2. margin负值实现单列表的多列排列
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>margin负值实现单列表多列显示</title> 6 <style> 7 * { 8 margin: 0; 9 } 10 11 div.container { 12 width: 500px; 13 margin: 50px auto; 14 background-color: orange; 15 } 16 17 li { 18 font-size: 16px; 19 line-height: 1.5em; 20 } 21 22 li.col2 { 23 margin-left: 150px; 24 } 25 26 li.col3 { 27 margin-left: 300px; 28 } 29 30 .top { 31 margin-top: -3em; 32 } 33 34 </style> 35 </head> 36 37 <body> 38 <div class="container"> 39 <ul> 40 <li>第1项</li> 41 <li>第2项</li> 42 <li>第3项</li> 43 <li>第4项</li> 44 <li>第5项</li> 45 <li>第6项</li> 46 </ul> 47 </div> 48 <div class="container"> 49 <ul> 50 <li>第1项</li> 51 <li>第2项</li> 52 <li class="col2">第3项</li> 53 <li class="col2">第4项</li> 54 <li class="col3 ">第5项</li> 55 <li class="col3">第6项</li> 56 </ul> 57 </div> 58 <div class="container"> 59 <ul> 60 <li>第1项</li> 61 <li>第2项</li> 62 <li class="col2 top">第3项</li> 63 <li class="col2">第4项</li> 64 <li class="col3 ">第5项</li> 65 <li class="col3">第6项</li> 66 </ul> 67 </div> 68 <div class="container"> 69 <ul> 70 <li>第1项</li> 71 <li>第2项</li> 72 <li class="col2 top">第3项</li> 73 <li class="col2">第4项</li> 74 <li class="col3 top ">第5项</li> 75 <li class="col3">第6项</li> 76 </ul> 77 </div> 78 </body> 79 </html>
个人认为这个例子简直是margin负值的经典教程,非常简单的应用,但是直指margin负值的本质。
二、margin的百分比数值
当margin属性的值为百分数时,其总是以父元素的width为基数进行计算。
请看下面这个demo,当初折磨了我N久的。。。只怪我知道得太晚了,说多了都是泪啊。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>margin的百分数值</title> 6 <style> 7 .container { 8 width: 500px; 9 height: 300px; 10 margin: 50px auto; 11 background-color: orange; 12 border: 1px solid black; 13 } 14 15 .box { 16 width: 250px; 17 height: 150px; 18 margin-left: auto; 19 margin-right: auto; 20 background-color: cyan; 21 } 22 23 .box1 { 24 margin-top: 75px; 25 margin-bottom: 75px; 26 padding: 5px; 27 } 28 29 .box2 { 30 margin-top: 25%; 31 margin-bottom: 25%; 32 padding: 5px; 33 } 34 </style> 35 </head> 36 37 <body> 38 <div class="container"> 39 <div class="box box1"> 40 <p>父元素的高度为300px,子元素的高度为150px,只要margin-top和margin-bottom都为75px,这个盒子就能垂直居中。</p> 41 <p>OK,居中啦!!!</p> 42 </div> 43 </div> 44 <div class="container"> 45 <div class="box box2"> 46 <p>既然子元素的高度是父元素高度的50%,那么只要margin-top和margin-bottom都为25%,应该也能垂直居中。</p> 47 <p>额,这什么鬼?说好的居中呢?</p> 48 </div> 49 </div> 50 </body> 51 </html>
友情提示,padding属性的值为百分数时,也是以父元素的width为基数计算的。
三、垂直方向上margin的合并
只有普通文档流中块级元素的垂直外边距才会发生外边距合并;行内元素、浮动元素或绝对定位元素之间的外边距不会合并。
垂直方向上的margin只要亲密接触就会合并,也只有亲密接触才会合并。
来看例子:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>垂直方向上的margin合并</title> 6 <style> 7 .container { 8 width: 500px; 9 height: 300px; 10 margin: 50px auto; 11 background-color: orange; 12 } 13 14 .box { 15 width: 300px; 16 height: 200px; 17 margin-left: auto; 18 margin-right: auto; 19 background-color: cyan; 20 margin-top: 25px; 21 padding: 5px; 22 } 23 24 .border { 25 border: 1px solid black; 26 /*padding: 1px;*/ 27 } 28 </style> 29 </head> 30 31 <body> 32 <div class="container"> 33 <div class="box"> 34 <p>父元素的margin-top为50px,子元素的margin-top为25px;</p> 35 <p>咦,子元素的margin-top呢?为什么都顶到父元素上边界了?</p> 36 <p>额,因为父元素与子元素的margin-top亲密接触了呀,所以它们合并在一起了啊。</p> 37 </div> 38 </div> 39 <div class="container border"> 40 <div class="box"> 41 <p>可是我就是想让子元素距离父元素的上边界25px啊,我不想让它们合并呀。</p> 42 <p>很简单,给父元素加个边框,它们就无法亲密接触了,就不会合并了啊。</p> 43 <p>或者给父元素设置padding也是可以的喔。</p> 44 </div> 45 </div> 46 </body> 47 </html>
消除垂直方向上margin合并的方法:给父元素加border或者加padding,打破父元素与子元素margin之间的亲密接触即可。
margin合并的规则:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>margin合并规则</title> 6 <style> 7 .container { 8 width: 300px; 9 height: 500px; 10 margin: 50px; 11 background-color: orange; 12 float: left; 13 border: 1px solid black; 14 } 15 16 .box1,.box2,.box3, 17 .box4,.box5,.box6 { 18 width: 200px; 19 height: 150px; 20 margin: 30px auto; 21 background-color: cyan; 22 text-align: center; 23 line-height: 150px; 24 } 25 26 .box1 { 27 margin-bottom: 30px; 28 } 29 30 .box2 { 31 margin-top: 20px; 32 } 33 34 .box3 { 35 margin-bottom: 30px; 36 } 37 38 .box4 { 39 margin-top: -30px; 40 } 41 42 .box5 { 43 margin-bottom: -30px; 44 } 45 46 .box6 { 47 margin-top: -50px; 48 background-color: green; 49 } 50 51 p { 52 width: 220px; 53 margin:10px auto; 54 font-size: 16px; 55 line-height: 1.5; 56 } 57 58 </style> 59 </head> 60 61 <body> 62 <div class="container"> 63 <div class="box1">box1</div> 64 <div class="box2">box2</div> 65 <p>box1的margin-bottom为30px,box2的margin-top为20px,两个margin都是正数,取绝对值大的。</p> 66 </div> 67 <div class="container"> 68 <div class="box3">box3</div> 69 <div class="box4">box4</div> 70 <p>box3的margin-bottom为30px,box4的margin-top为-30px,两个margin一正一负,相加。</p> 71 </div> 72 <div class="container"> 73 <div class="box5">box5</div> 74 <div class="box6">box6</div> 75 <p>box5的margin-bottom为-30px,box6的margin-top为-50px,两个margin都是负数,取绝对值大的。</p> 76 </div> 77 </body> 78 </html>
1. 两个margin都是正数,取绝对值大的;
2. 一个margin是正数,另一个margin是负数,相加;
3. 两个margin都是负数,取绝对值大的。