元芳,你怎么看CSS中的margin合并?

什么是margin合并?

块级元素的上外边距(通常)与下外边距有时会合并为单个外边距,这样的现象称为“margin合并”。

从定义上,我们可以看出如下两点:

  1. 块级元素。但不包括浮动(float)和绝对定位(relative)元素——尽管这二者可以使元素块级化;
  2. 只发生在垂直方向。严格来说,应该是【只发生在和当前文档流方向的相垂直方向上】——但是默认文档流是水平的

这一幕,让我不禁想起了BFC:有记为证
传说,只要满足了以下任一要求即可触发BFC:

  • body 根元素
  • 浮动元素:float 除 none 以外的值
  • 绝对、固定定位元素:position (absolute、fixed)
  • display 为 inline-block、table-cells、flex
  • overflow 除了 visible 以外的值 (hidden、auto、scroll)

可见,BFC和margin合并之间有些相似:作用于“流”、对元素与“其他元素”位置有影响

fg

margin合并也有三大场景

(1)相邻兄弟元素的margin合并

//css
p {margin: 1rem 0;}
//html
<p>第一行</p>
<p>第二行</p>

则第一行和第二行之间的间距仍为1rem。

(2)父级和第一个/最后一个子元素
事实上,在开发中大多时候你都要忍受这种父子margin合并带来的麻烦。
比如你在官网有一张大图(二维码),配合有一个很大的网站标题。由于这个标题一般在头图中间的某位置,因此,我们很自然会想到使用margin-top定位。
然后问题就来了:头图居然“掉”了下来!
当时笔者遇到这个问题时查阅资料后才发现这就是父子margin合并。这里大家需要清楚这个“合并”的概念:父元素没有出一点力,而子元素出了全部的力,最终margin却全部合到了父元素上。简单点说就是虽然是在子元素上设置的margin-top,但实际上等于是作用在父元素上。

但这里需要注意一点:“等于”并不是“就是”。
我们如果使用getComputedStyle方法获取父元素的margin-top值,还是在css中设置的值,而并非margin合并后的“表现值”。

那如何阻止这里的margin合并呢?
同样的,只要满足了以下任一要求即可触发:

  • 父元素设置为块状格式化上下文
  • 父元素设置border-top(bottom)值
  • 父元素设置padding-top(bottom)值
  • 父元素和第一个(最后一个)子元素之间添加内联元素进行分隔
  • 父元素设置height、min-height或max-height(此针对margin-bottom合并)

所以,对于上面所说的问题,只要在父元素中添加:

扫描二维码关注公众号,回复: 11160594 查看本文章
//css
xxx {overflow: hidden;}

即可(其原理就是overflow属性为父级元素块状格式化上下文)
【…其实笔者觉得这里还是“套用的”BFC,为所有子元素套上一个容器,避免对外面(其它)元素产生干扰】

说到这里,笔者不得不提一句:jQuery中有个$().slideUp() / $().slideDown()方法,如果在使用此动画时,发现这块内容在动画开始或结束时会跳那么一下,那基本上可以说是布局存在margin合并了。不过这个更确切的说是“margin合并被阻止”导致的。其解决办法就是在使用时对元素设置overflow: none;即可

(3)空块级元素的margin合并

//css
.father {overflow: hidden;}
.son {margin: 1rem 0;}
//html
<div class="father">
	<div class="son"></div>
</div>

此时,父级元素这个div自身高度仅1rem,因为子级元素的margin-top和margin-bottom合并在一起了撑开的距离。

其实,像文前面所说的,就算兄弟不相邻,合并也是可以发生的——但前提是中间“插手”的也是个会合并的家伙:比如div;所以,这里空块级元素的margin合并特性即使自身没有设置margin也是会发生的。

解决:

  • 设置垂直方向的border
  • 设置垂直方向的padding
  • 里面添加内联元素(直接物理Space是没用的…)
  • 设置height或者min-height

fg

margin合并的计算规则?

我们可以把margin的合并规则总结为“正正取大值”、“正负值相加”、“负负取最负”三句“秘诀”。
——不管是对元素自身,还是对两个元素之间关系,都适用。

fg

margin合并的意义

margin(尤其是margin-top)这样设计,其实在实际内容呈现中有重要意义——但由于其“怪异”,导致现在广为流传的说法:“margin-top合并bug”,这其实是不正确的。

<h2>文章标题</h2>
<p>段落1</p>
<p>段落2</p>
<ul>
	<li>列表1</li>
	<li>列表2</li>
</ul>

这里的h2、p、ul标签默认全部是有垂直方向的margin值的,而且单位全部都是em。

首先解释-下为何 需要 margin 值。其实原因很简单, css世界的设计本意就是图文信息展示,有了默认的 margin 值,我们的文章、新闻就不会挤在一起,垂直方向就会层次分明、段落有致,阅读体验就会好!为何使用em作为单位也很好理解,大家应该知道浏览器默认的子亏大小是可以自定义的吧(例如,默认的是16 像素),假如我们设置成更大号的字号,同时HTML标签的margin是像素大小,则会发生文字变大但是间距不变的情况,原本段落有致的阅读体验必然又会变得令人室息。em作为相对单位,则可以让我们的文章或新闻无论多大的字体都排版良好。可以看到,HTML标签默认内置的CSS属性值完全就是为了更好地进行图文信息展示而设计的。
我们平时进行网站开发的时候都会重置各种默认的margin尺寸,这是件需要好好审视的事情,对于绝大多数网站,确实需要做这样的处理,因为这些网站鲜有传统的图文信息展示区域。但是,如果你的站点是博客、新闻门户或公众号文章,我们应该做的是统一标签的margin大小,而不是一股脑地重置成0。

下面说说margin合并的意义。对于兄弟元素的margin合并其作用和em类似,都是让图文信息的排版更加舒服自然。假如说没有margin合并这种说法,那么连续段落或列表之类首尾项间距会和其他兄弟标签成1:2关系;文章标题距离顶部会很近,而和下面的文章详情内容距离又会很开,就会造成内容上下间距不一致的情况。 这些都是糟糕的排版体验。而合并机制可以保证元素上下间距一致, 无论是h2标题这种margin偏大的元素,还是中规中矩的p元素,因为“正正取大值”。
父子 margin 合并的意义在于:在页面中任何地方嵌套或直接放入任何裸div,都不会影响原来的块状布局。div 是网页布局中非常常用的一个元素,其语义是没有语义,也就是不代表任何特定类型的内容,是一- 个通用型的具有流体特性的容器,可以用来分组或分隔。由于其作用就是分组的,因此,从行为表现上来看,一个纯粹的

元素是不能够也不可以影响原先的布局的。现在有如下一段HTML:

<div style= "margin-top:20px;"></div>

那么请问:现在要在上面这段HTML的外面再嵌套一层div元素, 假如说现在没有父子margin合并,那这层新嵌套的div岂不阻断了原本的兄弟margin合并?很有可能间距就会变大,妥妥地影响了原来的布局,这显然就违背了div的设计作用了。所以才有了父子margin合并,外面再嵌套一层div元素就跟没嵌套一样, 表现为margin-top:20px就好像是设置在最外面的div元素上-样。
自身margin合并的意义在于可以避免不小心遗落或者生成的空标签影响排版和布局。
例如:

<p>第一行</p>
<p></p>
<p></p>
<p>第二行</p>

其实它和下面这段代码效果是一样的:

<p>第一行</p>
<p>第二行</p>

但若是没有margin合并,上面代码中间怕是要隔了许多“莫名其妙的”空格了吧。


知道了margin合并的意义和作用,你完全可以在列表中设置保留上下margin:

margin-top: 15px;
margin-bottom: 15px;

而不是只战战兢兢的使用margin-top。

原创文章 198 获赞 554 访问量 10万+

猜你喜欢

转载自blog.csdn.net/qq_43624878/article/details/105830939
今日推荐