发表于: 2017-04-25 23:18:47
2 1120
【css-08】margin负值在页面布局中有哪些应用?
小课堂【武汉-143期】
分享人:庄引
1.背景介绍
CSS中的负边距(negative margin)就是将margin属性的值设为负值,在CSS布局中很多的布局方法都依赖于负边距。 三列布局是前端设计中很常见的页面布局方式,三列一般分别是居左的导航,且宽度固定;主列是居中的主要内容,宽度自适应;附加列一般是广告等额外信息,居右且宽度固定。 圣杯布局和双飞翼布局都可以实现这种三列布局, 圣杯布局和双飞翼布局是前端工程师必须掌握,因为它既能体现你懂HTML结构又能体现出你对DIV+CSS布局的掌握,也能带来带来最好的用户体验。
2.知识剖析:
margin的作用是什么?
外边距属性定义元素周围的空间。通过使用单独的属性,可以对上、右、下、左的外边距进行设置。也可以使用简写的外边距属性同时改变所有的外边距。--W3School
设置外边距会在元素外创建额外的"空白"。“空白”通常是指不能放其他元素且父元素背景可见的区域。--CSS权威指南(第三版)P217
外边距(margin)。可以设置盒子与相邻元素的间距。--CSS设计指南(第三版)P64
3.常见问题:
margin 为什么取负值 ?
首先必须先理解margin移动的基准点,而margin的值决定移动的方向和数值。
margin的参考线有两类,一类是top、left,它们以外元素作为参考线,另一类是right、bottom,它们以自身作为参考线。
简单点说就是:当margin-top、margin-left为负值的时候,会把元素上移、左移,同时元素在文档流中的位置也发生相应变化,这点与position:relative的元素设置top、left后元素还占据原来位置不同当margin-bottom、margin-right设为负值的时候,元素本身没有位置变化,后面的元素会上移、左移。
红色箭头表示正值时候的移动方向,当margin为负值的时候就反方向移动
总地来说,就是当margin-fonttop、left为负值的时候与参考线的距离减少,当margin-right、bottom为负值的时候参考线就向左、上面移动。
5.编码实战
float + 负margin 方式--圣杯布局(QQ空间,新浪微博)
圣杯布局 是典型的 CSS 布局问题,有着众多的解决方案。如果你不熟悉圣杯布局的历史,这篇文章 能够提供很好的总结,并连接了几个众所周知的解决方案。
圣杯布局由页头 (header),中间部分 (center),页脚 (footer),和三栏组成。中间的一栏是主要内容,左边和右边提供如广告、导航的链接。
圣杯布局 是典型的 CSS 布局问题
圣杯布局由页头 (header),中间部分 (container),页脚 (footer),和三栏组成。中间的一栏是主要内容,左边和右边提供如广告、导航的链接。
两边带有固定宽度中间可以流动(fluid);
中间一栏 (主要内容) 在 HTML 源码中应该首先元素出现;
使用的 HTML 标记尽量少,仅需一个额外的
div
标签仅需非常简单的 CSS,带上最少的兼容性补丁
当页面内容不够充满页面时,页脚应“粘”在底部。
第1步 建立骨架
先完成 header, footer 和 container 三个 主要的div
<header></header>
<div id="container">
</div>
<footer></footer>
container 的内边距设置为左右两栏各自的宽度:
第2步 加入三栏
此时我们有了基本框架,可以把三栏加入进去了。
<header></header>
<div id="container">
<div id="center" class="column">
</div>
<div id="left" class="column">
</div>
<div id="right" class="column">
</div></div>
<footer>.</footer>
接着我们给每一栏配上合适的宽度,并将它们设为浮动。同时我们需要清除 footer 的上下环境,以免遭跟上面三栏一起浮动。
#container .column {
position: relative;
float: left;
}
#center {
width: 100%;
}
#left {
width: 200px;
/* LC width */
right: 200px;
/* LC width */
margin-left: -100%;
}
#right {
width: 150px;
/* RC width */
margin-right: -100%;
}
footer {
clear: both;
}
中间一栏的 100% 宽是基于它的父容器 container 的宽度而言的,由于 container 设置了内边距,因此中间栏看起来就处在了网页的中间,但左右两栏由于排在中间栏的后面,且因空间不够被挤到了中间栏的下面,如下图所示:
第3步 把左侧栏放上去
中间栏已经就位,剩下的事情就是把左右两栏放上去了,接下来我们先放左侧栏。首先,我们先将它的外边距设置为 -100%,这样一来,由于浮动的关系,左侧栏就能上位,与中间栏交叠在一起,并占据了左边。而右侧栏由于左侧栏的上位,自动向前浮动到了原来左侧栏的位置。
接着我们要用到相对定位属性(relative),并设置一个与左侧栏等宽的偏移量:
#container .column {
position: relative;
float: left;
}
#left {
width: 200px;
/* LC width */
right: 200px;
/* LC width */
margin-left: -100%;
}
可以看到,它设置的 right
属性就是相对于 container 的右边线向左偏移 200px,如此一来,它就完美地跑到了 container 左内边距的位置,也就是我们希望它呆的地方,如下图所示:
第4步 把右侧栏放上去
最后,我们需要把右侧栏放上去,此时只需利用上面的原理把他放到 container 的右外边距的位置即可,我们需要再一次设置一个负外边距的值,它等于右侧栏的宽度:
#right {
width: 150px;
/* RC width */
margin-right: -100%;
}
双飞翼布局:
双飞翼布局源自淘宝UED,现在查看下淘宝首页DOM结构,就能找到双飞翼布局的身影。
通过缩放页面就可以发现,随着页面的宽度的变化,这三栏布局是中间盒子优先渲染,两边的盒子框子固定不变,即使页面宽度变小,也不影响我们的浏览。
如果你有了那么一点理解以后,我们来看看圣杯布局的实现:
第一步:给出HTML结构:
<header><h1>Header内容区</h1></header>
<div class="container">
<div class="middle"><p>中间弹性区</p></div>
<div class="left"><p>左边栏</p4></div>
<div class="right"><p>右边栏</p></div>
</div>
<footer><p>Footer内容区</p></footer>
写结构的时候要注意,父元素的的三栏务必先写中间盒子。因为中间盒子是要被优先渲染嘛~并且设置其自适应,也就是width:100%。
第二步:给出每个盒子的样式
header {
width: 100%;
height: 40px;
background-color: darkseagreen;
}
.container {
height: 200px;
overflow: hidden;
}
.middle {
width: 100%;
height: 200px;
background-color: deeppink;
float: left;
}
.left {
width: 200px;
height: 200px;
background-color: blue;
float: left;
}
.right {
width: 200px;
height: 200px;
background-color: darkorchid;
float: left;
}
footer {
width: 100%;
height: 30px;
background-color: darkslategray;
}
第三步:看此时的效果图

三栏并没有在父元素的一行显示,因为中间盒子我们给了百分之百的宽度。所有左右两个盒子才会被挤下来。
那么如何让它们呈现出一行三列的效果呢?那就要让左边的盒子要到中间盒子的最左边,右边的盒子到中间盒子的最右边。换个想法,如果中间盒子不是100%的宽度,那么按照文档流,左边的盒子一定会在中间盒子的后面显示,接着显示右边的盒子。但是现在中间盒子是满屏了的,所以左右两个盒子被挤到下一行显示。我们要做到的是让左右两个盒子都上去。此时,CSS的负边距(negative margin)该大显身手了。
第四步:利用负边距布局
1.让左边的盒子上去
需要设置其左边距为负的中间盒子的宽度,也就是。这样左盒子才可以往最左边移动。
2.让右边的盒子上去
需要设置其左边距为负的自己的宽度,也就是
.right {margin-left:-200px;}
。这样右盒子才可以在一行的最右边显示出自己。
第五步:看此时的效果图

到这里,是不是感觉很有成就感?但是很遗憾的告诉你,还没结束哦!
我们现在的确是硬性的实现了固比固布局。但是要记住,中间盒子是自适应的宽度,所以中间盒子里的内容会被左右盒子给压住一部分。
比如现在我给中间盒子加很多的内容,大家看看效果图:

所以,我们的工作还没停止。
第六步:让中间自适应的盒子安全显示
首先:利用父级元素设置左右内边距的值,把父级的三个子盒子往中间挤。
代码如下:
.container{ padding: 0 200px;}
这里的200px是左右盒子的宽度。
效果如下:

我们可以看到,左右两边的内边距是有了,但是中间盒子上的内容还是被压着。
其次:给左右两个盒子加一个定位,加了定位之后左右两个盒子就可以设置left和right值。
代码如下:
.left{ position: relative; left: -200px;}
.right{position: relative;right: -210px;

现在,圣杯布局终于搞定了,也实现了我们要的效果,左右侧的盒子固定,中间盒子自适应,而且中间盒子的内容完全不受影响。
margin负值配合float在布局中独孤求败。
6.扩展思考
当浏览器缩小到一定程度时,这个布局可能会被破坏,怎么解决?
可以在body上添加min-width属性解决
圣杯布局其实和双飞翼布局是什么关系?
事实上,圣杯布局其实和双飞翼布局是一回事。它们实现的都是三栏布局,两边的盒子宽度固定,中间盒子自适应。它们实现的效果是一样的,差别在于其实现思想。
圣杯布局的优点?
- 使主要内容列先加载。
- 允许任何列是最高的。
- 没有额外的div。
- 需要的hack很少。
双飞翼布局非常灵活,通过调整css代码可以实现各种布局。例如,利用双飞翼布局实现了一套栅格布局系统。
双飞翼布局的优点:
- DOM按照主、子、附加列的顺序加载,实现了重要内容先加载。
- main部分是自适应宽度的,很容易在定宽布局和流体布局中切换。
- 在浏览器上的兼容性非常好,IE5.5以上都支持。
- 实现了内容与布局的分离,即Eric提到的Any-Order Columns.
- 任何一栏都可以是最高栏,不会出问题。
- 需要的hack非常少。
7.参考文献
圣杯布局和双飞翼布局(前端面试必看) - 简书
(2)关于「圣杯布局」 - 天道酬勤 - SegmentFault
8.更多思考:
圣杯布局与双飞翼布局在实现上的异同点:
- 俩种布局方式都是把主列放在文档流最前面,使主列优先加载。
- 两种布局方式在实现上也有相同之处,都是让三列浮动,然后通过负外边距形成三列布局。
- 两种布局方式的不同之处在于如何处理中间主列的位置:圣杯布局是利用父容器的左、右内边距定位;双飞翼布局是把主列嵌套在div后利用主列的左、右外边距定位。
两者相比较,双飞翼布局虽然多了一个div,却减少了相对定位属性的代码,个人认为双飞翼布局在实现思路和代码简洁度上都要比圣杯布局更好一些。
评论