CSS Margin 布局技巧
CSS 里有一个重要的东西,叫 CSS 盒模型,它几乎能贯穿我们学习 CSS 的整个阶段,如下图所示,就是我们所说的盒子模型:
.png)
(注:图片来源 MDN )
“盒模型”中最外层透明的区域就是 margin所在,它会将其他区域从盒子模型内容中推开。
margin 一共有四个属性值, margin-top 、margin-right 、margin-bottom 和 margin-left 属性,也可以设置简写属性 margin。
margin 看起来比较简单,但是,它其实有自己的奥妙所在,比如我们在布局中经常遇到 margin 重叠效果等,接下来我们来看看 margin 究竟有什么神奇所在吧。
margin 重叠
margin 重叠指的是垂直重叠,重叠的意思是,当我们规定一个模块的 margin-bottom 与 紧邻着的下一个模块的 margin-top 它们会发生重叠,它们之间不会出现较大的空白。因为代码会取两个值之间较大的那个,比如 第一个模块设置margin-bottom: 50px ,第二个模块设置 margin-top: 100px 那么第一个模块的 margin-bottom 则不会起作用,起作用的则是 第二个模块的 margin-top 也就是说他们之间的空白间距是 100px ,可能会有疑问,那 50px 跑哪里去了,其实是被包含在 100px 里面了 这就是所谓的 margin 重叠。
以下情况下,margin 会发生重叠:
- 相邻的兄弟元素
- 完全空盒子
- 父元素与它的第一个或最后一个子元素
相邻的兄弟元素重叠
上述我们所描绘的情况就是相邻兄弟之间的 margin 重叠。
如下示例,有三个 div 元素。第一个 div 的顶部与底部的 margin 分别是 50px 第二个 div 的顶部与底部 margin 分别是 20px ,第三个 div 的顶部与底部 margin 是 3em。 那么出现的重叠情况是,第一个与第二个的间距是 50px, 因为第二个元素的顶部小于第一个底部的 margin,取两者之间较大的。第二个元素与第三个元素之间的间距则是 3em ,同理 3em 大于第二个元素的 底部 20px。
<div class="box1">模块一</div>
<div class="box2">模块二</div>
<div class="box3">模块三</div>
div {
border: 1px solid #ddd;
height: 200px;
}
.box1 {
margin: 50px 0;
}
.box2 {
margin: 20px 0;
}
.box3 {
margin: 3em 0;
}
在线 demo
完全空盒子
什么是完全空盒子,就是盒子里面什么也没有就是完全的空盒子,没有内容也没有子元素,它顶部与底部的 margin 可能会相互重叠,如下示例,一个 class 为 empty 的元素顶部与底部的 margin 分别为 50px , 但是第一个元素与第三个元素之间的间距并没有 100px ,而是 50px 。这就是空盒子造成的 margin 重叠,如果我们在空盒子里面写入内容就会阻止 margin 合并。
<div class="wrap">
<div class="box1">模块一</div>
<div class="box2 empty"></div>
<div class="box3">模块三</div>
</div>
.wrap {
border: 5px dotted #000;
}
.box1, .box3 {
height: 100px;
background: #f60;
}
.empty {
margin: 50px 0;
}
在线 demo
父元素和第一个或最后一个子元素
一开始接触布局时,我们可能会经常碰到这样的问题,我们给子级设置一个margin-top 值,如果没有清除 BFC 的话,常常看到的错觉是这样的:

从图上可以看到,第一项与最后一项与父元素的 margin 齐平,好像是子元素与父元素之间没有 20px 的 margin 一样。
<div class="box">
<div class="child"></div>
<div class="child"></div>
</div>
.box {
background: green;
}
.child {
height: 100px;
background: red;
margin: 20px;
}
这是因为子节点上的 margin 会随着父元素上的任何一边 margin 相互重叠,从而最终位于父元素的外部,造成的错觉像是父元素向下 margin 或者向上 margin 一样。
注意:在 CSS 中,只指定了重置方向的 margin 重叠,即元素的顶部和底部的 margin 重叠。左右是不会发生重叠的。
还有一点就是,margin 只在块的方向上发生重叠,比如段落之间。
阻止 margin 发生重叠
如果一个元素是绝对定位,或者是浮动的, 它的 margin 永远不会发生重叠, 因为他已经脱离文档流了。
如果是一个完全空的盒子,给它设置一个 border 或者 padding ,那么这个空盒子的 margin 则不会发生重叠。
<div class="wrap">
<div class="box1">模块一</div>
<div class="box2 empty"></div>
<div class="box3">模块三</div>
</div>
.wrap {
border: 5px dotted #000;
}
.box1, .box3 {
height: 100px;
background: #f60;
}
.empty {
margin: 50px 0;
/* border: 1px solid transparent; */
padding: 1px;
}
在线 demo
那么为什么加上 border 或 padding 就可以了呢? 那是因为如果一个空盒子加上 border 或者 padding 后就有高度了就变成非空盒子了。如果我们在代码布局上,我们标记一个为空的段落元素,如果不想让他造成与其他模块较大的空白,这时候我们做的 margin 重叠就有了一定的意义。
对于父元素和第一个或者最后一个子元素的 margin 重叠,如果我们向父级添加 border 或者 padding 那么子级上的 margin 则会保留。
创建格式化上下文(BFC)
BFC (Block Formatting Context) 格式化上下文 ,是 Web 页面中盒模型布局的css渲染模式,是一个独立的渲染区域或者是一个隔离的独立容器。
BFC 可以阻止边距的重叠。我们可以在父级元素上添加BFC,从而可以避免与子级元素的 margin 重叠。
<div class="box">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
.box {
background: green;
overflow: hidden; /* 创建BFC */
/*overflow: auto*/
/*display: flow-root*/
}
.child {
height: 100px;
background: #f60;
margin: 20px;
}

display: flow-root 是 CSS3 新出来的一个属性,用来创建一个无副作用的 BFC。将 overflow 的属性的值设置为 auto 或者 hidden 也会产生同样的效果,只不过有时候这俩属性值会带来一些副作用。
布局时的 margin 策略
由于我们知道上下 margin会发生重叠,所以我们在网站布局时,会采用单独给一边加 margin 值的策略,要么是 margin-top 要么是 margin-bottom 这两个在布局时最好是一个元素上别同时存在,当然指的是相邻的元素。那如果是父子级身上的 margin 重叠的情况下,我们最好还是采用上述清除 margin 的办法,当然现代浏览器的发展以及一些布局方法的更新,我们可以采用 flex 布局 和 grid 布局 抛除掉 margin 的使用。当前具体问题还得具体分析,我相信我们做的例子多了 会有更深刻的认识。
百分比 margin
在 CSS 中使用百分比的时候,它必须是某个元素的百分比,也就是说我们必须有一个参考元素。使用百分比设置的 margin(或者padding) 始终是父元素内联大小(水平写入模式下单宽度)的百分比。
<div class="wrapper">
<div class="box">
I have a margin of 10%.
</div>
</div>
* {
box-sizing: border-box;
}
.wrapper {
border: 5px dotted black;
width: 200px;
height: 400px;
}
.box {
background-color: rgb(55, 55, 110);
color: white;
padding: 20px;
border-radius: .5em;
margin: 10%;
}
body {
font: 1.4em/1.3 "Gill Sans", "Gill Sans MT", Calibri, sans-serif;
margin: 2em 3em;
}
在线 demo
后记
只是简单的介绍了下,平时遇到 margin 重叠的几种情况,以及我们该如何处理。还是那句话, CSS 博大精深,虽然容易入门但是后期的东西真的是让我们随时随地的去学习了,所以我们在平时的学习过程中,要记得多加练习,多多总结。