margin负值对布局的影响
在文档流中,元素的最终边界是由margin决定的,margin为负的时候就相当于元素的边界向里收,文档流认的只是这个边界,不会管你实际的尺寸是多少。
在文档流中,如果元素前面的元素设置了负margin,则他会以流的形式跟上去。所以将元素都设置负margin后,就会产生覆盖。
margin设置移动时的参考:margin的参考线有两类,一类是top、left,它们以外元素作为参考线,使自己移动。另一类是right、bottom,它们以自身作为参考线。让兄弟元素移动
总地来说,就是当margin-top、left为负值的时候与参考线的距离减少,当margin-right、bottom为负值的时候参考线(不是本身,是相隔的那个)就向左、上面移动。
表现
虽然margin可以应用到所有元素,但display属性不同时,表现也不同
- block元素可以使用四个方向的margin值
- inline元素使用上下方向的margin值无效
<style> * { margin: 0; padding: 0; } span { border: 1px solid black; margin: 100px; } </style> <span>inline上下的margin是无效的</span>
- inline-block使用上下方向的margin负值看上去无效
- 其中只是vertical-align:baseline / bottom是无效的,top / middle是有效的
<style> * { margin: 0; padding: 0; } input { margin-top: -100px; vertical-align: bottom; } </style> <input type="text" value="inline-block的上下margin负值是无效果的">
[注意]inline-block使用上下方向的margin负值只是看上去无效,这与其默认的vertical-align:baseline有关系,当垂直对齐的属性值为其他值时,则会显示不同的视觉效果
重叠
margin负值并不总是后面元素覆盖前面元素,它与元素display属性有关系
- 两个block元素重叠时,后面元素可以覆盖前面元素的背景,但无法覆盖其内容
* { padding: 0; margin: 0; } .top { width: 100px; height: 100px; background-color: yellow; } .bot { width: 100px; height: 100px; background-color: blue; margin-top: -100px; } </style> //这里的top不会被覆盖 <div class="top">top</div> <div class="bot"></div>
- 当两个inline元素,或两个line-block元素,或inline与inline-block元素重叠时,后面元素可以覆盖前面元素的背景和内容
.st { background-color: yellow; opacity: .8; } .sb { background-color: blue; margin-left: -30px; opacity: .8; } </style> <div class="top">top</div> <div class="bot"></div> <span class="st">sttttttttttttttttt</span> <span class="sb">sbssssssssssssssssssss</span>
- 当inline元素(或inline-block元素)与block元素重叠时,inline元素(或inline-block元素)覆盖block元素的背景,而内容的话, 后面的元素覆盖前面的元素
<style> span { background: red; margin-left: -5px; } div { background: blue; width: 100px; float: left; height: 100px; } </style> //浮动后span元素会在div后面,加上margin-left负值后,span覆盖div的内容和背景 <span>我是内联元素</span> <div>我是块级元素</div>
综上所述,个人理解,在普通流布局中,浏览器将页面布局分为内容和背景,内容的层叠显示始终高于背景。block元素分为内容和背景,而inline元素或inline-block元素,它本身就是内容(包括其背景等样式设置)
当元素都浮动时
- 全部设置margin负值时,会正常移动元素,但是相互浮动的元素会覆盖一部分浮动的元素
- 这里并不是我们想的那样,如果将若干元素都设置同样的margin,他们都移动相同的距离,但是还是会相互遮盖
<style> div { border: 1px solid black; margin-top: -50px; width: 200px; height: 200px; } </style> <div class="box1">1</div> <div class="box2">2</div> <div class="box3">3</div>
- 如果只给浮动元素的一个元素加负的margin,则他会向内联一样
<style> div { float: left; width: 100px; height: 100px; background: red; } div:nth-child(1) { background: blue; } div:nth-child(2) { background: green; margin-left: -10px; } </style> <div class="box1">1</div> <div class="box2">2</div> <div class="box3">3</div>
定位元素
- 对于相对定位,通过margin的值偏移,该元素原来的位置会空出来,但是通过left等偏移,该元素原来的位置依然存在
- 但是绝对定位元素就不同了,他将所有定位元素都加上一样的负margin,那么将是整体移动,不会彼此遮盖
``` <style> * { margin: 0; padding: 0; } div { border: 1px solid black; position: absolute; width: 200px; height: 200px; } .box2 { left: 200px; margin-left: -100px; } .box3 { left: 400px; margin-left: -100px; } </style> <div class="box1">1</div> <div class="box2">2</div> <div class="box3">3</div> ```
对自身的影响
- 当元素不存在width属性或者(width:auto)的时候,负margin会增加元素的宽度。
<style> .container { margin: 0 auto; width: 500px; border: 1px #ccc solid; margin-bottom: 20px; } .box1 { margin-left: -20px; /* margin-bottom: -100px; */ } </style> <div class="container"> //box1不设置宽度或者width: auto;这样设置margin负值就可以增加他的宽度 <div class="box1"> I dont have the width </div> </div>
对内联元素
- 如果只改变一个内联元素的margin为负值,紧跟其后的所有连续的内联元素,也会移动,不会改变布局
<style> * { margin: 0; } .box2 { margin-left: -20px; background: red; } span { border: 1px solid black; } </style> <span class="box1">1111</span> <span class="box2">2222</span> <!-- <div>0000</div> --> <span class="box3">3333</span>
双飞翼布局
- 将中间的布局放在最前面,因为我们利用margin负值会覆盖他前面的元素,而中间的元素宽度最大,刚好被覆盖。
- 左边的布局margin-left: -100%;
- 右边的布局marfin-left: -自身宽度
- 将中间元素用一个div包裹,使中间内容不被覆盖,设置子元素margin,来撑开与父元素的距离则可以做到。
<style> * { padding: 0; margin: 0; } .content { margin: 10px; } .left { width: 300px; height: 200px; float: left; background: red; margin-left: -100%; } .middle { height: 200px; background: blue; /* 这个表示距离父元素的距离 */ margin: 0 310px; } .content-main { width: 100%; float: left; } .right { width: 300px; height: 200px; float: left; background: skyblue; margin-left: -300px; } </style> <div class="content"> <div class="content-main"> <div class="middle"></div> </div> <div class="left"></div> <div class="right"></div> </div>
圣杯布局
- 布局和双飞翼相同,但是避免中间的元素内容被覆盖,需要设置padding来使内容在中间显示,而不被覆盖。
<style> * { margin: 0; padding: 0; } /* .content { padding: 0 310px; } */ .left { width: 300px; height: 200px; float: left; background: red; margin-left: -100%; /* position: relative; left: -310px; */ } .middle { width: 100%; height: 200px; float: left; box-sizing: border-box; padding: 0 310px 0 310px; background: blue; } .right { width: 300px; height: 200px; float: left; background: skyblue; margin-left: -300px; /* position: relative; right: -310px; */ } </style> <div class="content"> <div class="middle">333333333333</div> <div class="left"></div> <div class="right"></div> </div>
圣杯和双飞翼异同
圣杯布局和双飞翼布局解决的问题是一样的,都是两边定宽,中间自适应的三栏布局,中间栏要在放在文档流 前面以优先渲染。
- 两种方法基本思路都相同:首先让中间盒子 100% 宽度占满同一高度的空间,在左右两个盒子被挤出中间盒子所在区域时,使用 margin-left 的负值将左右两个盒子拉回与中间盒子同一高度的空间。接下来进行一些调整避免中间盒子的内容被左右盒子遮挡。
- 主要区别在于 如何使中间盒子的内容不被左右盒子遮挡:
- 圣杯布局的方法:设置父盒子的 padding 值为左右盒子留出空位,再利用相对布局对左右盒子调整位置占据 padding 出来的空位;
- 双飞翼布局的方法:在中间盒子里再增加一个子盒子,直接设置这个子盒子的 margin 值来让出空位,而不用再调整左右盒子。
简单说起来就是双飞翼布局比圣杯布局多创建了一个 div,但不用相对布局了,少设置几个属性。
等高布局
- 利用flex
- 利用table-cell,将每一列都设置display:table-cell;但是有关table的都不可以设置margin属性
- 利用margin-bottom负值和padding-bottom正值
- margin-bottom负值是让父元素可以在子元素下边距之上,可以让padding-bottom增加的内容溢出。然后在使用overflow:hidden来将其隐藏。
- padding-bottom正值是增加子元素的内容高度,来弥补margin-bottom负值引起的父元素在子元素之上。并且视觉上仍然可以显示子元素内容高度增加。
盒子模型的经典问题
margin叠加问题:
- 兄弟元素之间设置的margin-top,margin-bottom,如果有一个设置为负margin,那么它会把正值和负值计算后的值设置为margin,如果两个值都是负值,那么取那个较小的负值。
- 父子元素的叠加,由于子元素的margin-top,margin-bottom会传递给父元素,就会与父元素自己设置的margin进行叠加成一个较大的margin,忽略那个较小的margin值
margin传递问题
margin-top的传递。如果块级元素的顶部线和父元素的顶部线重叠,那么这个块级元素的margin-top值会传递给父元素。如果顶部不重叠就不会出现这种情况
<style> div:nth-child(1) { background: red; width: 100px; height: 100px; margin-bottom: -20px; overflow: hidden; } div:nth-child(2) { background: blue; width: 100px; height: 100px; margin-top: -10px; opacity: 0.5; } </style> //间距为-20px <div>1</div> <div>2</div>
margin-bottom的传递。如果块级元素的底部线和父元素的底部线重叠,并且父元素的高度是auto,那么这个块级元素的margin-bottom值会传递给父元素。
解决方法:
- 给父元素设置padding-top\padding-bottom
- 给父元素设置border
- 触发BFC,给父元素设置overflow: auto / hidden / scroll
一般来讲:margin一般是用来设置兄弟元素之间的间距。
padding一般是设置父子元素之间的间距。