浅析margin负值之美
目录
- 背景
-
- margin负值的原理
- 2.1 基于参考线的原理图
- 2.2 实际demo
- 2.2.1 margin-left负值的表现
- 2.2.2 margin-top负值的表现
- 2.2.3 margin-right负值的表现
- 2.2.4 margin-bottom负值的表现
-
- margin 负值在布局中的运用
- 3.1 绝对定位 + 负边距—>水平垂直居中效果
- 3.2 去除列表最后一项的右边距
- 3.3 去除列表最后一个li元素的border-bottom
- 3.4 左右列固定宽度,中间列自适应布局
- 3.5 多列等高布局
1. 背景
之前学习margin时更多接触到的是正值,负值可能平日使用较少,基本没怎么见过。最近接触到布局才发现原来margin负值的作用原来如此巨大。刚接触margin负值实现的一些布局时虽然知道如此可以实现某些布局,但具体是怎么实现的?相信有不少人都有过和我相同的困惑。查阅一些资料,博客后终于解开了心中的迷惑,特整理与需要之人分享。
2. margin负值的原理
2.1 基于参考线的原理图
为便于理解margin负值,这里引入参考线的概念。参考线即为margin移动的基准点,而margin的值即为在参考线基础上移动的距离。
margin的参考线分为两类:
- margin-left / margin-top 以外元素作为参考线
- margin-right / margin-bottom 以自身作为参考线
具体来说:
- left负值就是以包含块(Containing Block)内容区域的左边或该元素左侧相连元素margin的右边为参考线
- top负值就是以包含块(Containing Block)内容区域的上边或该元素上方相连元素margin的下边为参考线
- right负值是以元素自身的border-right为参考线
- bottom负值是以元素自身的border-bottom为参考线
下面这张图(图片来源于网络)可以更为直观的表现了margin依据参考线的移动,其中而红色箭头方向为margin正值时移动的反向,margin负值则相反。
margin移动原理图2.2 实际demo
公共HTML代码:
<div class="one">one</div>
<div class="two">two</div>
公共CSS代码:
.box {
width:250px;
height: 250px;
border: 1px black solid;
}
.box div {
width:100px;
height: 100px;
}
.one {
background:gray;
}
.two {
background:orange;
}
2.2.1 margin-left负值的表现
<style>
.one,two {
float: left;
}
.two {
/*margin-left: 50px;*/
/*margin-left:-50px;*/
}
</style>
- 初始位置:
-
margin-left: -50px位置:
margin-left:-50px位置
设置float:left使得div.one和div.two向左浮动,同时设置div.two的margin-left:-50px;
div.two的参考线就是div.one的右边距(margin-right)外侧,于是div.two向左移动使之与参考线的距离减少50px。
- margin-left:50px位置:
2.2.2 margin-top负值的表现
<style>
.two {
/*margin-top:-50px;*/
/*margin-top:50px;*/
}
</style>
- 初始位置:
- margin-top:-50px位置:
设置div.two的margin-top:-50px;
div.two的参考线就是div.one的下外边距(margin-bottom)外侧,于是div.two向上移动使之与参考线的距离减少50px。
- margin-top:50px位置:
2.2.3 margin-right负值的表现
<style>
.one {
float:left;
/*margin-right:-50px;*/
/*margin-right:50px;*/
}
.two {
float:left;
}
</style>
- 初始位置:
- margin-right:-50px位置:
设置float:left使得div.one和div.two向左浮动,同时设置div.one的margin-right:-50px;
div.one的参考线就是div.one自身右边距(margin-right)外侧,于是div.one向左移动使之与参考线的距离减少50px。
- margin-right:50px位置:
2.2.4 margin-bottom负值的表现
<style>
.one {
/*margin-bottom:-50px;*/
/*margin-bottom:50px;*/
}
</style>
- 初始位置:
- margin-bottom:-50px位置:
设置div.one的margin-bottom:-50px;
div.one的参考线就是div.one的下外边距(margin-bottom)外侧,于是div.one向上移动使之与参考线的距离减少50px。
- margin-bottom:50px位置:
3. margin 负值在布局中的运用
3.1 绝对定位 + 负边距—>水平垂直居中效果
HTML:
<div class="parent">
<div class="child"></div>
</div>
CSS:
<style>
* {
margin:0;
padding:0;
}
.parent {
width:400px;
height:200px;
background-color: #e0e0e0;
}
.child {
width: 100px;
height: 50px;
background-color: #f40;
}
</style>
- 初始效果图:
绝对定位 + 负边距—>水平垂直居中效果:
.parent {
position:relative;
}
.child {
position:absolute;
top:50%;
left:50%;
margin-top:-25px;
margin-left:-50px;
}
绝对定位 + 负边距—>水平垂直居中效果
3.2 去除列表最后一项的右边距
项目中经常会使用浮动列表展示信息,为了美观通常为每个列表之间设置一定的间距(margin-right),当父元素的宽度固定,每一行的最右端的li元素的右边距就多余了,去除的方法通常是为最右端的li添加class,设置margin-right:0; 这种方法需要动态判断为哪些li元素添加class,麻烦!!!利用负margin就可以实现下面这种效果:
HTML:
<div id="test">
<ul>
<li>子元素1</li>
<li>子元素2</li>
<li>子元素3</li>
<li>子元素4</li>
<li>子元素5</li>
<li>子元素6</li>
</ul>
</div>
CSS:
<style>
body, ul, li {
padding: 0;
margin: 0;
}
ul, li {
list-style: none;
}
#test {
width: 320px;
height: 210px;
background: #CCC;
}
#test ul li {
width: 100px;
height: 100px;
background: #F60;
margin-right: 10px;
margin-bottom: 10px;
float: left;
}
</style>
- 初始效果图:
-
添加margin负值后效果:
#test ul { margin-right: -10px; }
同理可去除列表第一项的左边距!
列表项两端对齐优雅的方法应该是内层元素和外层元素之间包一层元素,设置margin-right=-10px,使块级元素框的水平总和总共为210px - 10px = 200x ,等于父元素的宽度即可
3.3 去除列表最后一个li元素的border-bottom
列表中我们经常会添加border-bottom值,最后一个li的border-bottom往往会与外边框重合,视觉上不雅观,往往要移除。
HTML:
<div >
<ul class="test">
<li>Test</li>
<li>Test</li>
<li>Test</li>
<li>Test</li>
<li>Test</li>
</ul>
</div>
CSS:
<style>
body,div,ul {
margin:0;
padding:0;
}
ul,li {
list-style:none;
}
.test {
margin-top:20px;
width:390px;
background-color: #F4F8FC;
border:2px solid #D7E2EC;
border-radius:3px;
overflow: hidden;
}
.test li {
height:25px;
line-height:25px;
padding:5px;
border-bottom:1px dashed red;
}
</style>
- 初始效果图:
-
为 li添加margin负值后:
.test li { margin-bottom:-1px; }
3.4 左右列固定宽度,中间列自适应布局
此例适用于左右两栏宽度固定,中间栏宽度自适应的布局。由于网页的主体部分一般在中间,很多网页都需要中间列优先加载,而这种布局刚好满足此需求。
HTML:
<div class="main">
<div class="main-body">Main</div>
</div>
<div class="left">Left</div>
<div class="right">Right</div>
CSS:
<style>
body {
margin:0;
padding:0;
min-width:600px;
}
.main {
float:left;
width:100%;
}
.main-body {
height:200px;
margin:0 210px;
border:2px solid red;
background-color:#888;
}
.left, .right {
float:left;
width: 200px;
height: 200px;
background-color: #F60;
}
.left{
margin-left:-100%;
/*当margin以left作为参考时,
其是以包含块内容区域的左边
或者左方相连元素的margin-right作为参考线*/
}
.right{
margin-left:-200px;
}
</style>
- 最终效果图:
3.5 多列等高布局
此案例关键之处在于给每个框设置大的底部内边距,然后用数值相似的负外边距消除这个高度。这会导致每一列溢出容器元素,如果把外包容器的overflow属性设为hidden,列就在最高点被裁切。
HTML:
<div id="wrap">
<div id="left">
<p>style="height:50px"</p>
</div>
<div id="center">
<p>style="height:100px"</p>
</div>
<div id="right">
<p>style="height:200px"</p>
</div>
</div>
CSS:
<style>
body,p{
margin:0;
padding:0;
}
#wrap{
overflow:hidden;
width:700px;
margin:0 auto;
}
#left,#center,#right{
margin-bottom:-200px;
padding-bottom:200px;
}
#left {
float:left;
width:200px;
height:50px;
background:#777;
}
#center {
float:left;
width:300px;
height:100px;
background:#888;
}
#right {
float:right;
width:200px;
height:200px;
background:#999;
}
p {color:#FFF;text-align:center}
</style>
- 最终效果图: