深入 CSS 负边距
老实说,个人从来没有重视过 CSS,觉得很简单,没有可学之处。但随着使用和认识的深入,才发现 CSS 也博大精深。加上 CSS3 的出现,以前需要 JavaScript 的地方,现在用 CSS 亦可以轻松实现。相信未来,CSS 一定能大放异彩!这次一起和大家聊一聊 CSS 中的负边距。
负边距的特点
在正式介绍负边距之前,我们先回顾一下文档流。所谓的文档流,指的是元素排版布局过程中,元素会自动从左往右,从上往下的流式排列。并最终窗体自上而下分成一行行, 并在每行中按从左至右的顺序排放元素。脱离文档流即是元素打乱了这个排列,或是从排版中拿走。
脱离文档流
要使一个元素脱离文档流有两种方式:
- 使用浮动(float):值为 left、right 均会使元素脱离文档流
- 使用定位(position):值为 absolute、fixed 的元素脱离文档流,其它不脱离文档流
未脱离文档流元素
<div class="box1">A</div>
<div class="box2">B</div>
<div class="box3">C</div>
我们先来看一看正边距,当我们给三个 div 分别设置上边距时,自然而然,三个元素都会隔开一定间隙。
当我们给三个 div 分别设置负上边距时,这时我们看到元素将被拉进指定的方向。
我们可以这样来思考,既然正边距是相隔距离;那值为负,自然就反过来了,就是相叠距离。
当我们设置某个元素的 margin-right
和 margin-bottom
为负值,而非 margin-left
和 margin-top
时,这时元素并不会如你所想的那样向右或下移动,而是将后续的元素拖拉进来,覆盖本来的元素。
造成这两种不同现象的原因时文档流只会向左和向上,不可能向右和向下
如果没有设定 width 属性,设定负 margin-left
和 margin-right
会将元素拖向对应的方向,并增加宽度,此时的 margin 的作用就像 padding 一样。没有设置width 的元素的宽度值是由包围元素的宽度来计算出来的,然后减去 margin,所以就会得到实际上比原始元素更宽的值。
总结
-
margin-left
和margin-top
:影响自身元素,将向指定方向偏移 -
margin-right
和margin-bottom
:影响相邻元素,将其拖入指定方向
已脱离文档流元素
绝对定位元素(absolute)
设置的 margin 的方向为 top 或者 left
当设置负值的 margin 的方向为 top 或者 left 的时候,元素也会按照设置的方向移动相应的距离。
设置的 margin 的方向为 bottom 或者 right
由于设置绝对定位的元素已经脱离了标准文档流,所以,设置 margin-right/bottom 对后面的元素并没有影响。
浮动元素(float)
其实浮动元素和未脱离文档流的元素在负边距上表现类似,只不过浮动有左和右两种浮动。对应文档流,我们可以称浮动元素为浮动流。
当负值的 margin 的方向与浮动流方向一直时,则元素会往对应的方向移动对应的距离。
当负值的 margin 的方向与浮动流方向相反时,则元素本身不动,元素之前或者之后的元素会向该元素的方向移动相应的距离。
总结
浮动流不像文档流只是向上和向左,它是可以向左和向右的。除了这点外,其实和未脱离文档流元素表现差不多。
负边距的应用
三列布局(static 元素)
li {
line-height: 1.5em;
}
.col2 {
margin-left: 200px;
}
.col3 {
margin-left: 400px;
}
.top {
margin-top: -3em;
}
<ul>
<li class="col1">第一列第一排</li>
<li class="col1">第一列第二排</li>
<li class="col2 top">第二列第一排</li>
<li class="col2">第二列第二排</li>
<li class="col3 top">第三列第一排</li>
<li class="col3">第三列第二排</li>
</ul>
这种例子主要利用了负上边距会将元素上移,同时不会像 relative 元素仍然占据之前的位置的特点。
多列布局之清除最后一列右边距(static 元素)
我们常常会遇到如图所示的布局,他要求每一列距离右边一小段间隔,而最后一列没有间隔。最常见的解决方案就是给最后一列加上一个class
,设置其右边距为零。但现在我们有一种更酷的解决方案,不需要增加一个新的class
(尤其在循环时,不太容易确定元素给其加上class
)。
.container {
width: 860px;
margin: 0 auto;
margin-top: 80px;
border: 1px solid #ccc;
overflow: hidden;
}
ul {
list-style-type: none;
margin-right: -20px;
}
li {
float: left;
width: 200px;
margin-top: 5px;
margin-bottom: 5px;
margin-right: 20px;
background: #00f;
color: #fff;
}
<div class="container">
<ul>
<li>子元素1</li>
<li>子元素2</li>
<li>子元素3</li>
<li>子元素4</li>
<li>子元素5</li>
<li>子元素6</li>
<li>子元素7</li>
<li>子元素8</li>
</ul>
</div>
这种例子主要利用了没有给定
width
的元素,设定负 margin-left/margin-right 会增加元素的宽度。
左边固定,右边自适应的两列布局(float 元素)
.container {
float: left;
width: 100%;
margin-right: -300px;
background: burlywood;
}
.container .content {
margin-right: 310px;
}
.sidebar {
float: left;
width: 300px;
background: #f00;
}
<div class="container">
<div class="content">
中间内容区域
</div>
</div>
<div class="sidebar">侧边栏区域</div>
这种例子主要利用了给一个浮动元素加上相反的负边距时,另一浮动元素会认为前者的宽度减少相应的边距值。但有意思的是,前者的宽度并没有受影响,他还是占据了屏幕100%的宽度,另一元素就像是浮动在他右边的区域之上。
圣杯布局(float 元素)
以前学习CSS的时候,就听说了圣杯布局。当时觉得特高大上,“圣杯”一词完全升华了布局本身,上升到了一个神话高度。事实上,他就是利用了本文的主题负边距来实现的。废话不多说了,直接上代码。
.container {
padding: 0 300px 0 200px;
}
.content {
float: left;
width: 100%;
background: #f00;
}
.left {
position: relative;
left: -200px;
float: left;
width: 200px;
margin-left: -100%;
background: #0f0;
}
.right {
position: relative;
right: -300px;
float: left;
width: 300px;
margin-left: -300px;
background: #00f;
}
<div class="container">
<div class="content">中间内容区域</div>
<div class="left">左侧边栏区域</div>
<div class="right">右侧边栏区域</div>
</div>
注意点:
- 中间内容放在最上面,保证先渲染
- 精髓还是负边距
双飞翼布局(float 元素)
说完圣杯布局,我们再来聊一聊双飞翼布局。又是一个听起来高大上的布局名,由淘宝首创。两个布局实现的效果都是一样,只不过文档结构和样式略有区别,当然核心还是负边距的应用。
.container {
float: left;
width: 100%;
background: #f00;
}
.content {
margin-left: 200px;
margin-right: 300px;
}
.left {
float: left;
width: 200px;
margin-left: -100%;
background: #0f0;
}
.right {
float: left;
width: 300px;
margin-left: -300px;
background: #00f;
}
<div class="container">
<div class="content">中间内容区域</div>
</div>
<div class="left">左侧边栏区域</div>
<div class="right">右侧边栏区域</div>
区别:
- 圣杯布局是中间栏在添加相对定位,并配合 left 和 right 属性,效果上表现为三栏是单独分开的
- 双飞翼布局是在中间栏的 div 中嵌套一个 div,内容写在嵌套的 div 里,然后对嵌套的 div 设置 margin-left 和 margin-right,效果上表现为左右两栏在中间栏的上面,中间栏还是 100% 宽度,只不过中间栏的内容通过 margin 的值显示在中间
- 通过两者实现的截图红色区域可以很明显看到两者区别
参考
上一篇: MySQL优化 之 Discuz论坛优化