8.8 相邻兄弟的margin折叠与避免

8.8.1 规则详情

(1)规则描述:同一BFC内,兄弟两个元素垂直方向margin进行折叠。

(2)详情描述:无论上方或下方元素是否存在相关padding或border,上方元素margin-bottom与下方元素margin-top总是相邻,所以设置padding与border无法避免折叠。


8.8.2 不合理的折叠示例

页面初始代码。设置div1的margin-bottom为20px,div2的margin-top为 20px,期望总间距40px。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>小步教程</title>
    <style>
        
        .div1{
            background-color: #0aaa76;
            width: 200px;
            height: 30px;
            margin-bottom: 20px;
        }

        .div2{
            background-color: #4aa6fc; 
            width: 200px;
            height: 30px;   
            margin-top: 20px;         
        }
    </style>
</head>
<body>
    <div class="div1">
        小步教程 
    </div>

    <div class="div2">
        xiaobuteach.com
    </div>
</div>
</body>
</html>

期望效果

img

实际结果不符合期望

img


8.8.3 兄弟margin折叠的本质

兄弟margin-top折叠之BFC示意图

img

同一BFC内,兄元素margin-bottom与弟元素margin-top相邻。


8.8.4 BFC避免折叠

(1)在兄与弟内部同时新建BFC,也无法避免折叠。BFC示意图如下。

img

即使两者都在内部新建BFC,兄div的margin-bottom与弟div的margin-top仍属于BFC-X,仍然相邻。此方法无效。

(2)直接设置双方padding或border也无效,盒子示意图如下,两者始终相邻。

img


(3)间接解决方法。其中一个div再添加父元素,父元素设置新建BFC,即避免两个margin在同一BFC。原先的两个兄弟元素最终已经不是兄弟。

img

绿色实线表示弟div添加的父div,虚线表示它内部新建的BFC对象。两个元素的margin区域不在同一个BFC。

完整代码如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>小步教程</title>
    <style>
        
        .div1{
            background-color: #0aaa76;
            width: 200px;
            height: 30px;
            margin-bottom: 20px;       
        }

        .div2{
            background-color: #4aa6fc; 
            width: 200px;
            height: 30px; 
            margin-top: 20px;           
        }

        .div2-wrap{
            display: flow-root;
        }
    </style>
</head>
<body>
    <div class="div1">
        小步教程
    </div>

    <div class="div2-wrap">
        <div class="div2">
            www.xiaobuteach.com
        </div>
    </div>
</div>
</body>
</html>

div2-wrap内部新建BFC,实现期望效果。同理可以在div1外加div1-wrap并新建BFC。


8.8.5 多重margin折叠

上述代码取消div2-wrap的flow-root设置,运行结果仍然发生折叠。因为发生多重margin折叠:第1次折叠,div2的margin穿透到div2-wrap,这是父子折叠;第2次折叠,上步产生的margin区域又与div1发生兄弟折叠。所以仍然无法避免折叠。

示例代码

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>margin折叠 | 小步教程</title>
    <style>
        body {
            margin: 0;
        }

        .div1 {
            border-bottom: 1px solid #666;
        }

        .div2-wrap {
            margin-top: 20px;

            background-color: #999;
            width: 300px;
        }

        .div2 {
            margin-top: 20px;

            background-color: #0aaa76;
            width: 250px;
        }

        .div2-1 {
            margin-top: 30px;

            background-color: #4aa6fc;
            height: 30px;
            margin-left: 20px;
        }

        .div2-2 {
            margin-top: 20px;
            background-color: #ed7d31;
            height: 30px;
            margin-left: 20px;
        }


        .div3 {
            border-top: 1px solid #666;
        }
    </style>
</head>

<body>
    <div class="div1">div1</div>
    <div class="div2-wrap">
        <div class="div2">
            <div class="div2-1">div2-1 小步教程</div>
            <div class="div2-2">div2-2 xiaobuteach.com</div>
        </div>
    </div>
    <div class="div3">div3</div>
</body>

</html>

运行结果

img

元素div2-1的margin-top穿透父元素div2,并穿透其爷元素div2-wrap。


8.8.6 非新建BFC方法参考

下列方法根据具体需求场景选择使用。

方法1:合理运用折叠,合理设置margin值,实现目标效果。

方法2:直接合并margin值。相邻兄弟只设置一个元素的margin值,避免margin相邻。

方法3:改设padding值。padding值不会发生重叠。