margin系列之外边距折叠

不怀疑你也在工作中遇见过

几乎可以不用怀疑,前端工作中的你一定遇见过 margin 折叠。

不确定?别着急,你可能写过这样的代码:

CSS:

p{
    margin: 50px;
}

HTML:

<div id="demo">
    <p>我是一个华丽的段落,别看我文字少</p>
    <p>我是另一个华丽的段落</p>
</div>

 

大家觉得这 2p 之间会发生点什么?是会合体呢?还是分开?来看看 DEMO1 margin折叠

好吧,它们真的合体了。按照常规思路,这 2p 之间的空白应该是第一个 p 的 margin-bottom50px 加上第二 p 的 margin-top 50px,即 50 + 50px = 100px ,但结果总是出乎意料不是么?它们之间只剩下了 50px,这就是 margin折叠。所以任何人遇见过我都不会觉得意外,因为这样的Code看起来没有任何问题。

它们之间到底发生了些什么?

 2p 内部到底发生了什么,才会有这样的表现?

原文:The width of the margin on non-floating block-level elements specifies the minimum distance to the edges of surrounding boxes. Two or more adjoining vertical margins (i.e., with no border, padding or content between them) are collapsed to use the maximum of the margin values. In most cases, after collapsing the vertical margins the result is visually more pleasing and closer to what the designer expects.

翻译:外边距用来指定非浮动元素与其周围盒子边缘的最小距离。两个或两个以上的相邻的垂直外边距会被折叠并使用它们之间最大的那个外边距值。多数情况下,折叠垂直外边距可以在视觉上显得更美观,也更贴近设计师的预期。

 

从这段话中,我们能获得一些有用的信息:

  • 发生折叠需要是相邻的非浮动元素;
  • 折叠发生在垂直外边距上,即margin-top/margin-bottom;
  • 折叠后取其中最大的那个margin值作为最终值;

所以 DEMO1 中的 2p 符合折叠的条件,相邻且都不是浮动元素,于是它们就自然合体了。至于取最大的那个值作为折叠后的最终值,因为都是50px,所以无所谓谁谁谁了。

为什么会有margin折叠这样的设计?

从上文中,应该能知道个大概?在前面的文章中,我们说过,CSS的基本模型是排版。只是前端工程师现在做得更多的是 布局 而非 文字排版,但CSS并未界定这两者的区别。而 margin 折叠是为实现文本排版的段落间距而提供的特性。所以很多时候 margin 折叠的特性会带给我们诸多疑惑。

再回到 DEMO1 仔细看看,你会惊讶的发现,其实你只要设置每个 p 有相同的垂直外边距,由于发生会 margin 折叠,所有的 p 之间,及包含块与 p 之间的间隙都是相同的,非常美妙且实现简单,不是么?这正印证了我们引用 CSS1 中的那短话:多数情况下,折叠垂直外边距可以在视觉上显得更美观,也更贴近设计师的预期。

 

如何避免margin折叠?

我想肯定有人要问,那我不想有 margin 折叠的情况发生,该怎么办?其实从上面的规则中,我们已经可以抽出避免 margin 折叠的条件来。

  • margin 折叠元素只发生在块元素上;
  • 浮动元素不与其他元素 margin 折叠;
  • 定义了属性overflow且值不为visible(即创建了新的块级格式化上下文)的块元素,不与它的子元素发生margin 折叠;
  • 绝对定位元素的 margin 不与任何 margin 发生折叠。
  • 特殊:根元素的 margin 不与其它任何 margin 发生折叠;
  • 如果常规流中的一个块元素没有 border-toppadding-top,且其第一个浮动的块级子元素没有间隙,则该元素的上外边距会与其常规流中的第一个块级子元素的上外边距折叠。 可能有些绕,我们验证一下 DEMO3,在其第一个浮动子元素加个全角空格做间隙,来个反证 DEMO4
  • 如果一个元素的 min-height 属性为0,且没有上或下边框以及上或下内边距,且 height 为0或者 auto,且不包含行框,且其属于常规流的所有孩子的外边距都折叠了,则折叠其外边距。验证一下 DEMO5

这样干掉margin折叠

如果不想发生 margin 折叠,那么你可以根据上面的规则得到方法,不是么?我把它改成非块元素,让它浮动,让它绝对定位,让它 overflow:hidden DEMO6,用边框隔开它们 DEMO7...随你怎样,信手拈来。

今天状态不太好,有些地方写得欠妥,之后可能会修改一下。

BTW: 这篇文章里可能有不少之前文章中没出现过的名词,比如:块级上下文、行框、常规流,如果你对此不甚了解,可以先找资料看看,我以后会讲到。

 参考地址:http://www.ituring.com.cn/article/64583

posted @ 2015-11-02 14:25  Shimily  阅读(192)  评论(0)    收藏  举报