外边距折叠( Collapsing margins )详解

外边距折叠( Collapsing margins )1

在介绍 margin 特性的时候,简单的介绍了外边距折叠。

Collapsing margins,即外边距折叠,指的是毗邻的两个或多个外边距 (margin) 会合并成一个外边距。

其中所说的 margin 毗邻,可以归结为以下两点:

  • 这两个或多个外边距没有被非空内容paddingborder 或 clear 分隔开
  • 这些 margin 都处于普通流中2

下面详细的介绍其规则。

注:

  1. 详见:W3C CSS2.1 - 8.3.1 Collapsing margins
  2. 既 in-flow,非浮动元素,非定位元素(即规范内的非 absolutely positioned,这里不写为绝对定位元素是为了避免与样式设定中的绝对定位名词在中文中产生混淆)。

两个或多个毗邻的普通流中的块元素垂直方向上的 margin 会折叠

关键词解析

两个或多个

说明其数量必须是大于一个,又说明,折叠是元素与元素间相互的行为,不存在 A 和 B 折叠,B 没有和 A 折叠的现象。

毗邻

是指没有被非空内容、padding、border 或 clear 分隔开,说明其位置关系。

注意一点,在没有被分隔开的情况下,一个元素的 margin-top 会和它普通流中的第一个子元素(非浮动元素等)的 margin-top 相邻; 只有在一个元素的 height 是 "auto" 的情况下,它的 margin-bottom 才会和它普通流中的最后一个子元素(非浮动元素等)的 margin-bottom 相邻。

示例代码:

<div style="border:1px solid red; width:100px;">
    <div style="margin:50px 0; background-color:green; height:50px; width:50px;">
       <div style="margin:20px 0;">
           <div style="margin:100px 0;">B</div>
       </div>
    </div>
</div>

效果图:
margin 折叠举例

B

以上代码中,margin 会把 B 的包含块撑开。

如果一个元素的 height 特性的值不是 auto,那么它的 margin-bottom 和它子元素的 margin-bottom 不算相邻,因此,不会发生折叠。 margin-top 没有此限制,所以是 100px,margin-bottom 没有折叠,只有 50px。

垂直方向

是指具体的方位,只有垂直方向的 margin 才会折叠,也就是说,水平方向的 margin 不会发生折叠的现象。

折叠后 margin 的计算

1). 参与折叠的 margin 都是正值

例子:

<div style="height:50px; margin-bottom:50px; width:50px; background-color: red;">A</div>
<div style="height:50px; margin-top:100px; width:50px; background-color: green;">B</div>

示意图:

在 margin 都是正数的情况下,取其中 margin 较大的值为最终 margin 值。

2). 参与折叠的 margin 都是负值

当 margin 都是负值的时候,取的是其中绝对值较大的,然后,从 0 位置,负向位移。

示例代码:

<div style="height:100px; margin-bottom:-75px; width:100px; background-color: red;">A</div>
<div style="height:100px; margin-top:-50px; margin-left:50px; width:100px; background-color: green;">B</div>

示意图:

3). 参与折叠的 margin 中有正值,有负值

如果,毗邻的 margin 中有正值,同时存在负值会怎样呢?有正有负,先取出负 margin 中绝对值中最大的,然后,和正 margin 值中最大的 margin 相加。

示例代码:

<div style="height:50px; margin-bottom:-50px; width:50px; background-color: red;">A</div>
<div style="height:50px; margin-top:100px; width:50px; background-color: green;">B</div>

示意图:

上面的例子最终的 margin 应该是 100 + (-50) = 50px。

4). 相邻的 margin 要一起参与计算,不得分步计算

要注意,相邻的元素不一定非要是兄弟节点,父子节点也可以,即使不是兄弟父子节点也可以相邻。

而且,在计算时,相邻的 margin 要一起参与计算,不得分步计算。

一个复杂的实例:

<div style="margin:50px 0; background-color:green; width:50px;">
    <div style="margin:-60px 0;">
           <div style="margin:150px 0;">A</div>
    </div>
</div>
<div style="margin:-100px 0; background-color:green; width:50px;">
    <div style="margin:-120px 0;">
           <div style="margin:200px 0;">B</div>
    </div>
</div>

错误的计算方式:算 A 和 B 之间的 margin,分别算 A 和其父元素的折叠,然后与其父元素的父元素的折叠,这个值算出来之后,应该是 90px。依此法算出 B 的为 80px;然后,A和B折叠,margin 为 90px。

请注意,多个 margin 相邻折叠成一个 margin,所以计算的时候,应该取所有相关的值一起计算,而不能分开分步来算。

以上例子中,A 和 B 之间的 margin 折叠产生的 margin,是6个相邻 margin 折叠的结果。将其 margin 值分为两组:

  • 正值:50px,150px,200px
  • 负值:-60px,-100px,-120px

根据有正有负时的计算规则,正值的最大值为 200px,负值中绝对值最大的是 -120px,所以,最终折叠后的 margin 应该是 200 + (-120) = 80px。

浮动元素、inline-block 元素、绝对定位元素的 margin 不会和垂直方向上其他元素的 margin 折叠

浮动元素的 margin 在垂直方向上也不会发生 margin 折叠,即使和它相邻的子元素也不会。

<div style="margin-bottom:50px; width:50px; height:50px; background-color:green;">A</div>
<div style="margin-top:50px; width:100px; height:100px; background-color:green; float:left;">
    <div style="margin-top:50px; background-color:gold;">B</div>
</div>

示意图:

两个绿色的块儿之间,相距100px,而若 B 和它的浮动包含块发生 margin 折叠的话,金色的条应该位于绿色块的最上方,显然,没有发生折叠。

创建了块级格式化上下文1的元素,不和它的子元素发生 margin 折叠

以 “overflow : hidden” 的元素为例:

<div style="margin-top:50px; width:100px; height:100px; background-color:green; overflow:hidden;">
    <div style="margin-top:50px; background-color:gold;">B</div>
</div>

若 B 和它的 "overflow:hidden" 包含块发生 margin 折叠的话,金色的条应该位于绿色块的最上方,否则,没有发生。

示意图:

元素自身的 margin-bottom 和 margin-top 相邻时也会折叠

自身 margin-bottom 和 margin-top 相邻,只能是自身内容为空,垂直方向上 border、padding 为 0。

示例:

<div style="border:1px solid red; width:100px;">
    <div style="margin-top: 100px;margin-bottom: 50px;"></div>
</div>

以上代码运行后,我们讲得到的是红色边框的正方形,方框的宽高都应该是 100px,高度不应该是 150px。

示意图:

注:

  1. 既,Block formatting contexts,参考W3C CSS2.1 - 9.4.1 Block formatting contexts

引申阅读

相关浏览器对此部分内容引起的兼容性问题,可以参考:

测试环境

操作系统版本:Windows 7 Ultimate build 7600
浏览器版本:IE6
IE7
IE8
Firefox 3.6.10
Chrome 7.0.517.0 dev
Safari 5.0.2
Opera 10.62
测试页面: 
本文更新时间:2010-09-19
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
1. range-based for循环 range-based for循环是C++11引入的一种新的循环结构,它可以简化对容器和数组等数据结构的遍历。其语法形式如下: ``` for (declaration : range_expression) statement ``` 其中,declaration是一个变量声明,range_expression是一个表示要遍历的数据结构的表达式,statement是循环体中要执行的语句。 range_expression可以是任何具有begin()和end()成员函数的对象,包括STL容器、原生数组、指针等。循环的过程中,declaration将会被自动初始化为range_expression中的每个元素,从而实现遍历。 2. 结构化绑定(structured bindings) 结构化绑定是C++17引入的一种新的语言特性,它可以将一个复杂的数据结构拆分成若干个变量,使得代码更加简洁易读。其语法形式如下: ``` auto [var1, var2, ...] = expression; ``` 其中,var1、var2等表示要绑定的变量名,expression表示要进行拆分的数据结构。 结构化绑定可以用在任何支持解包的上下文中,例如函数返回值、for循环中的迭代器等。 3. 引用折叠(reference collapsing) 引用折叠是C++11引入的一种语言特性,用于规定C++中引用类型的组合方式。其规则如下: - 对于右值引用(Rvalue Reference,T&&),无论与左值引用还是右值引用相结合,都会得到右值引用类型。 - 对于左值引用(Lvalue Reference,T&),在不使用模板特化的情况下,左值引用与左值引用相结合得到左值引用,右值引用与左值引用结合得到右值引用类型。 - 在使用模板特化的情况下,引用折叠规则会发生变化。 引用折叠的主要作用是简化模板编程中的引用类型推导。它也是许多新特性的基础,例如完美转发、可变参数模板等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值