BFC及其作用

1. 什么是margin塌陷?

举个例子,像下面这种情况,上下两个盒子的间距按说是20px和40px,但实际都是20px,这就是塌陷。

      <div style="background-color:tomato;width:100px;height:100px;margin-bottom:20px;"> hello world</div>
      <div style="background-color:#bbb;width:100px;height:100px;margin-top:0px;"> hello world</div>
      <hr>
      <div style="background-color:tomato;width:100px;height:100px;margin-bottom:20px;"> hello world</div>
      <div style="background-color:#bbb;width:100px;height:100px;margin-top:20px;"> hello world</div>

其实这是CSS1.0故意设计的,因为这样符合平面设计师的要求。

2. 为什么塌陷时只出现在垂直方向?

在CSS出现之前使用的p标签,它要求每个段落之间有相同的间隔,所以当你对p标签设置了margin-topmargin-bottom你发现就会出现塌陷的情况,而且会取二者之中的最大值。

明白塌陷产生的条件也就明白了如何解决塌陷所带来的问题,那么塌陷产生的条件是什么?

首先是一个大前提:元素之间没有被非空内容、padding、border 或 clear 分隔开。然后有符合下面几种毗邻情况:

top margin of a box and top margin of its first in-flow child
(一个元素的 margin-top 和它的第一个子元素的 margin-top)

bottom margin of box and top margin of its next in-flow following sibling
(普通流中一个元素的 margtin-bottom 和它的紧邻的兄弟元素的的 margin-top)

bottom margin of a last in-flow child and bottom margin of its parent if the parent has ‘auto’ computed height
(一个元素( height 为 auto )的 margin-bottom 和它的最后一个子元素的margin-bottom)

top and bottom margins of a box that does not establish a new block formatting context and that has zero computed ‘min-height’, zero or ‘auto’ computed ‘height’, and no in-flow children
(一个没有创建 BFC、没有子元素、height 为0的元素自身的 margin-top 和 margin-bottom)

这段英文为摘抄

W3C规范这样描述:

In a block formatting context, each box’s left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch). This is true even in the presence of floats (although a box’s line boxes may shrink due to the floats), unless the box establishes a new block formatting context (in which case the box itself may become narrower due to the floats).
在BFC中,每个盒子的左外边框紧挨着包含块的左边框(若是从右到左的格式,则为紧挨右边框)。即使存在浮动也是这样的(尽管一个盒子的边框会由于浮动而收缩),除非这个盒子的内部创建了一个新的BFC浮动,盒子本身将会变得更窄)。

3. 如何解决margin塌陷?

方法已在代码中给出

    <div class="wrapper">
        <div class="content">
        </div>
    </div>
    * {
        margin: 0;
        padding: 0;
    }

    .wrapper {
        background-color: #000;
        margin-left: 100px;
        margin-top: 100px;
        width: 200px;
        height: 200px;
        /* float: left; */
        /* position: absolute; */
        /* display: inline-block; */
        /* display: flex; */
        /* 注意使用 overflow 溢出的部分会自动隐藏起来*/
        /* overflow: hidden; */
        /* 注意使用display: table虽然可以解决塌陷,但是cotainer的高度会失效 */
        /* display: table; */
        /* overflow: scroll; */
        /* overflow: scroll 溢出的部分会变成滚动,效果奇葩,应该没什么用 */
    }

    .content {
        /* 设置 margin-top: 150px;我们发现子级盒子会带着父级盒子一起往下移动,好像二者粘连到了一起或者说子级盒子好像没有了“顶”,此时会取wrapper和content的一个margin-top最大值。这种现象叫做margin塌陷,是经典BUG。 */
        margin-top: 150px;


        /* 在子元素中使用以下这些也可以解决塌陷 */
        /* float: left; */
        /* position: absolute; */
        /* display: inline-block; */
        width: 100px;
        height: 100px;
        background-color: #0f0;
        margin-left: 50px;
    }

4. margin合并(也叫margin折叠)

外边距折叠的例子如下

			<div class="wrapper"></div>
         <div class="content"></div>
.wrapper{
    height: 20px;
    background-color: #000;
    margin-top: 20px;
    margin-bottom: 200px;
}
.content{
    height: 20px;
    margin-top: 100px;
    background-color: #0f0;
}

参考:

解决方法

这里要分情况讨论,父子元素或是兄弟元素

参考:

  1. 使用数学方法(不解决)
  2. 引入BFC;给元素添加父级盒子并为其父级元素添加属性overflow: hidden;
  3. BFC可能会导致外边距折叠,同时也可以使用BFC来解决外边距折叠

这一开始听起来可能有些困惑,因为我们在前面讨论了BFC导致外边距折叠的问题。但我们必须牢记在心的是毗邻块盒子的垂直外边距折叠只有他们是在同一BFC时才会发生。如果他们属于不同的BFC,他们之间的外边距将不会折叠。所以通过创建一个新的BFC我们可以防止外边距折叠。
如下,之后给父级元素添加overflow: hidden;即可解决margin合并

      <div class="container">
         <div class="content1"></div>
         <div class="content2"></div>
      </div>
      <div class="container">
         <div class="content3"></div>
      </div>

效果如下

上面一段话的原文链接: https://www.w3cplus.com/css/understanding-block-formatting-contexts-in-css.html © w3cplus.com

5. 浮动元素(使用BFC来包含浮动)

浮动元素带有float的元素,最早用来实现类似于报纸图片环绕的布局

      <div class="wrapper">
         <div class="content">1</div>
         <div class="content">2</div>
         <div class="content">3</div>
         <div class="content">4</div>
         <div class="content">5</div>
         <div class="content">6</div>
         <div class="content">7</div>
         <div class="content">8</div>
         <div class="content">9</div>
      </div>
      <br>
      <div class="context1">YAMA</div>
      <div class="context2">YAMA</div>
      * {
         margin: 0;
         padding: 0;
      }

      .wrapper {
         background-color: aqua;
         /* width: 330px; */
         border: 2px solid black;
         /* 解决方法如下,在父级盒子添加overflow: hidden; */
         overflow: hidden;
      }

      .content {
         float: left;
         /*使元素站队、浮动*/
         color: #fff;
         margin-left: 10px;
         margin-bottom: 10px;
         background-color: black;
         width: 100px;
         height: 100px;
      }

      .context1 {
         float: left;
         width: 100px;
         height: 100px;
         background-color: red;
         color: white;
         opacity: 0.7;
      }

      .context2 {
         width: 150px;
         height: 150px;
         background-color: yellow;
         color: blue;
         /* 解决方法如下,在后面的元素变为行内块 */
         /* display: inline-block; */
         /* float: left; */
         /* float: right; */
      }

效果如图

此处我们注意到后面两个div好像具有层模型的特点,实际上不是,正确理解为:
浮动元素产生了浮动流,块级元素看不到所有产生了浮动流的元素。

注: 产生了BFC的元素、文本类属性(带有inline属性)的元素以及浮动元素都能看到浮动元素
(这里所指的看不到指的是在进行定位时会无视它而进行覆盖,就像层模型一样绝对定位)

(还需注意,如果设置position和float后由内容决定大小,打内部把元素转换成inline-block)

应用实例

在这里插入图片描述

6. 附实例

      <div class="wrapper">
         <div class="content">1</div>
         <div class="content">2</div>
         <div class="content">3</div>
         <p>YAMA</p>
      </div>
      * {
         margin: 0;
         padding: 0;
      }

      .wrapper {
         border: 10px solid black;
         /* overflow: hidden; */
      }

      .content {
         float: left;
         color: #fff;
         margin: 2px;
         background-color: black;
         width: 100px;
         height: 100px;
      }

      p {
         background-color: cadetblue;
         /* clear: both; */
      }

下图中上面的图片设置了overflow: hidden;,下面的没有

  • p标签属于块级元素会忽视float,在进行定位假设之前的浮动元素不存在(但是注意这里和之前的层模型区分开来)
  • 下面的图中的下面那部分是p标签添加clear: both;之后,意义是不允许该标签附近出现浮动对象,(相应的值还有左右),相当于清除了div标签的浮动特性。

7. 使用BFC来防止文字环绕

有时候一个浮动div周围的文字环绕着它(如下图中的左图所示)但是在某些案例中这并不是可取的,我们想要的是外观跟下图中的右图一样的。为了解决这个问题,我们可能使用外边距,但是我们也可以使用一个BFC来解决。

      <div class="container">
      <div class="floated">
         <img width="150px" src="https://ythdong.gitee.io/blog_image/JavaScript/%E6%8D%95%E8%8E%B720.PNG">
      </div>
      <p>YAMA YAMA YAMA YAMAYAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMAYAMA YAMA.
         YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMAYAMA YAMA
         YAMA YAMA
         YAMA YAMA YAMA YAMAYAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMAYAMA YAMA.
         YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMA YAMAYAMA YAMA
         YAMA YAMA.</p>
     </div>
    .floated {
        float: left;
        margin: 5px;
    }

    p {
        color: rgb(14, 13, 13);
        text-align: center;
        /* 解决方法如下 */
        overflow: hidden;

        /* 以下两种亦可,但效果不好 */
        /* display: inline-block; */
        /* clear: both; */
    }

8. 在多列布局中使用BFC

如果我们正在创建的一个多列布局占满了整个容器的宽度,在某些浏览器中最后一列有时候将会被挤到下一行。会发生这样可能是因为浏览器舍入(取整)了列的宽度使得总和的宽度超过了容器的宽度。然而,如果我们在一个列的布局中建立了一个新的BFC,它将会在前一列填充完之后的后面占据所剩余的空间。

      <div class="container">
         <div class="column">column 1</div>
         <div class="column">column 2</div>
         <div class="column">column 3</div>
      </div>
      .column {
         /* 父元素或者说视窗宽度的31.33%,下面的百分号也是如此 */
         width: 31.33%;
         background-color: green;
         float: left;
         margin: 0 0%;
      }

      .column:last-child {
         float: none;
         overflow: hidden;
      }

现在即使容器的宽度会有轻微的变化,但是布局也不会中断。当然,这并不是多列布局的最好选择,但它是防止最后一列下滑问题的一种方法。Flexbox在这种情况下可能是一个更好的解决方案,但是这应该要说明一下在这些情况下元素是如何表现的。

9. 两栏布局

实现两栏布局

10. 如何创建BFC?

https://developer.mozilla.org/zh-CN/docs/Web/Guide/CSS/Block_formatting_context

10.1. 总结

  1. 根元素(整个页面就是一个大的BFC);
  2. float为 left | right;
  3. overflow为 hidden | auto | scroll;
  4. display为 inline-block | table-cell | table-caption | flex | inline-flex;
  5. position为 absolute | fixed;

请注意,BFC并不是一个css属性,也不是一段代码,而是css中基于box的一个布局对象,它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。明确地,它是一个独立的盒子,并且这个独立的盒子内部布局不受外界影响,当然,BFC也不会影响到外面的元素

11. 参考

  1. 深度剖析Margin塌陷,BFC,Containing Block之间的关系
  2. 理解CSS中BFC
  3. css中的BFC
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值