一、前言
在学习CSS时,遇到的很多问题都是和margin有关,这个小怪兽总是出其不意的让我的界面排版变的混乱,还让人摸不着头脑,原因还是在于我对他的一些属性没有进行一个深入的了解,导致我在设计之初就忽略了一些潜在的bug。所以本文就margin属性以及常见的问题做一个总结归纳。
二、什么是margin
CSS 边距属性定义元素周围的空间。通过使用单独的属性,可以对上、右、下、左的外边距进行设置。也可以使用简写的外边距属性同时改变所有的外边距。——W3School
边界,元素周围生成额外的空白区。“空白区”通常是指其他元素不能出现且父元素背景可见的区域。——CSS权威指南
是不是看到以上的权威解释还是不明所以?别急,我画个图你就明白了。
还不明白?那好,我给你举个栗子,假设你住在一个别墅区,每栋别墅都是一个元素, 既然是别墅了那怎么着也得有个围墙吧(当然也可以没有,纯粹取决于业主喜不喜欢)。围墙就相当于上图的border边界(灰色区域),围墙与房子(上图的child即元素内容)之间的空间就是padding内边距(黄色区域),而围墙之外的空间就是外边距margin了(紫色区域),你可以当做是别墅与别墅之间的空间距离。margin存在的目的就是控制元素之间的间隔使页面排版更加的美观整齐,但它不属于元素的私有财产,在计算元素大小的时候可不要把margin算在内哦,毕竟你总不能把你家门口空气算作你自己的吧,那太霸道啦!看到这里你是不是对margin的作用范围有了大致的了解了,如果还不清楚,请继续往下看呀~
三、margin的特性
1、margin始终透明。这个特性其实可以这么理解,margin存在的目的就是为了隔开不同的元素使布局更加的美观,如果margin不是透明的就无法让不同的元素产生间隙达到隔开的目的还会影响其他布局,所以margin必须是透明的。
2、简写特性。margin属性可以设置4个值,分别是margin:top right bottom left;(可以按照顺时针的方式记忆,即:上右下左。顺序不能乱),这四个值也可以单独设置,即:margin-top、margin-bottom、margin-right、margin-left。除了可以单独设置之外,margin还可以进行简写(如非必要,不建议使用第三种简写),基本如下:
- margin只有一个值,表示top、right、bottom、left都是同一个值。例如:margin:10px等价于margin:10px 10px 10px 10px;
- margin只有两个值,第一值表示top、bottom的值,第二个值表示right、left的值。例如:margin:10px 20px等价于margin:10px 20px 10px 20px;
- margin只有三个值,第一个值表示top的值,第二个值表示right、left的值,第三个值表示bottom的值。例如:margin:10px 20px 30px等价于margin:10px 20px 30px 20px;
3、垂直方向外边距合并。块级元素的上外边距(margin-top)与下外边距(margin-bottom)有时会合并为一个外边距,这样的现象称为“margin合并”。只发生在与当前文档流方向相垂直的方向上,并且只能是块级元素。
四、margin合并的三种场景(纵向重叠)
1、相邻兄弟元素margin合并。这是margin合并中最常见、最基本的。例如:
p { margin: 1em 0; background-color: pink; } <p>第一行</p> <p>第二行</p>
效果图:
第一行和第二行的间距还是1em,因为第一行的margin-bottom和第二行的margin-top合并在了一起,并非上下相加。
2、父级和第一个/最后一个子元素合并。
1 <style> 2 .grandfather { 3 border: 2px solid red; 4 width: 300px; 5 height: 300px; 6 } 7 8 .father { 9 width: 200px; 10 height: 200px; 11 background-color: yellow; 12 } 13 14 .son { 15 margin: 2em 0; 16 background-color: pink; 17 } 18 </style> 19 20 <body> 21 <div class="grandfather"> 22 <div class="father"> 23 <div class="son">this is son</div> 24 </div> 25 </div>
效果图:
当给子元素添加外边距之后,父元素和子元素的上外边距(margin-top)发生了合并,导致父元素上外边距等同于变成了子元素的上外边距(合并的外边距值若都为正,则外边距取两者的最大值)造成了视觉上的父元素塌陷但实际父元素的上外边距的值并未改变。如何阻止这里margin合并的发生呢?
对于margin-top合并,可以进行如下操作(满足一个条件即可):
- 父级元素设置为块状格式化上下文元素(设置BFC),比如:给父级元素添加overflow:hidden;(推荐)
- 父元素设置border-top值;
- 父元素设置padding-top的值;
- 父元素和第一个子元素之间添加内联元素进行分隔
对于margin-bottom合并,可以进行如下操作(满足一个条件即可):
- 父级元素设置为块状格式化上下文元素
- 父级元素设置border-bottom值
- 父级元素设置padding-bottom值
- 父级元素和最后一个子元素之间添加内联元素进行分隔
- 父级设计height、min-height或max-height
上面例子中在.father中添加overflow:hidden效果如下:
3、空块级元素的margin合并。例如:
.father { overflow: hidden; } .son { margin: 1em 0; } <div class="father"> <div class="son"></div> </div>
效果图:
此时,.father所在的这个父级<div>元素高度仅仅是1em,因为.son这个空<div>元素的margin-top和margin-bottom合并在了一起。
四、margin负值问题
- margin-top和margin-left负值,元素向上、向左移动
- margin-right负值,右侧元素左移,自身不受影响
- margin-bottom负值,下方元素上移,自身不受影响
案列展示:
(1)margin-top为负值
(2)margin-left为负值
(3)margin-right为负值
(4)margin-bottom为负值
五、margin无效的问题
1、display:inline的非替换元素的垂直margin无效,对于内联替换元素垂直margin有效,并且没有margin合并的问题,所以图片永远不会发生margin合并。
2、表格中的<tr>和<td>元素或者设置display计算值是table-cell或table-row的元素的margin都是无效的。但是如果计算值是table-caption、table或者inline-table则没有此问题,可以通过margin控制外间距,甚至::first-letter伪元素也可以解析margin。
3、margin合并的时候,更改margin值可能是没有效果的。以父子margin重叠为例,假设父元素设置有margin-top:50px,则此时子元素设置margin-top:30px就没有任何效果表现,除非大小比50px大,或者是负值。
4、绝对定位元素非定位方向的margin值“无效”。因为绝对定位元素的渲染是独立的,普通元素和兄弟元素是互相关联的,但是绝对定位元素由于独立渲染无法和兄弟元素产生联系,因此margin无法影响兄弟元素定位,所以看上去就是无效的。
5、定高容器的子元素的margin-bottom或者宽度定死的子元素的margin-right的定位“失效”。这个现象的本质和和上面绝对定位元素非对立方margin值“无效”类似。原因在于,若想使用margin属性改变自身的位置,必须是和当前元素定位方向一样的margin属性才可以,否则,margin只能影响后面的元素或者父元素。
好了,总结了这么多,我想你应该对margin属性不陌生了吧,如果对你有帮助,就点个赞吧~
参考文档
https://www.cnblogs.com/zhangmingze/articles/4664074.html
https://blog.csdn.net/weixin_39855431/article/details/79929135
http://www.nowamagic.net/librarys/veda/detail/1608
https://blog.csdn.net/xun__xing/article/details/107334925
https://www.cnblogs.com/jjucap/p/5339725.html