CSS Margin 布局技巧
CSS
里有一个重要的东西,叫 CSS
盒模型,它几乎能贯穿我们学习 CSS
的整个阶段,如下图所示,就是我们所说的盒子模型:
(注:图片来源 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 博大精深,虽然容易入门但是后期的东西真的是让我们随时随地的去学习了,所以我们在平时的学习过程中,要记得多加练习,多多总结。