CSS经典问题:BFC(块级格式化上下文)和 flex:1

1,375 阅读5分钟

一、块级格式化上下文

块级格式化上下文(Block Formatting Context,BFC)是 Web 页面的可视 CSS 渲染的一部分,规定常规文档流(normal flow)块级盒子(block boxes) 的布局,BFC是一块独立渲染区域,这块区域内外的布局不会互相影响

常规流中块级盒子特性:

  • 盒子会在内联的方向上扩展并占据父容器在该方向上的所有可用空间,在绝大数情况下意味着盒子会和父容器一样宽
  • 每个盒子都会换行
  • 可以设置width 和 height生效
  • 内边距(padding), 外边距(margin)和 边框(border)会将其他元素从当前盒子周围“推开”

BFC中块级盒子特性:

  • BFC里面块级盒子会在垂直方向一个接一个的排列,和常规文档流的排列方式一致。
  • 在 BFC 中上下相邻的两个块级盒子的上下边距可能会重叠,创建新的 BFC 可以避免 外边距重叠
  • 计算 BFC 的高度时,需要计算浮动盒子的高度。(常有给浮动盒子父级创建BFC来计算高度)
  • BFC 区域不会与浮动的盒子发生重叠。
  • BFC 是独立的容器,容器内部元素不会影响外部元素。
  • 每个元素的左 margin 值和容器的左 border 相接触。

创建BFC的方式:

  • 文档的根元素(<html>
  • 浮动元素:float 值不为 none 
  • 绝对定位元素:position 值为 absolutefixed
  • overflow 值不为 visible或 clip,即为 hiddenautoscroll
  • display 值为flexinline-flex、 inline-blocktable-celltable-captiontableinline-tablegridinline-grid
  • 以上是常见的方式,其他的方式 MDN 上有详细的说明

应用:

1、解决父级元素高度塌陷

当父盒子内子元素设置浮动时,脱离了常规文档流,父盒子的自动高度就不会计算子浮动元素。

<body>
    <div class="father">
      <div class="child1"></div>
      <div class="child2"></div>
    </div>
 </body>
    <style>
      .father {
        background-color: red;
        border: 3px solid red;
      }

      .child1 {
        float: left;
        width: 200px;
        height: 200px;
        background-color: green;
      }

      .child2 {
        height: 100px;
        background-color: blue;
      }
    </style>

image.png

解决方式一:父级添加伪元素进行clear

      .father::after {
        content: "";
        clear: both; 
        display: block;
      }

image.png

解决方式二:父级创建BFC

  .father {
        background-color: red;
        border: 3px solid red;

        overflow: hidden;
      }

2、BFC与浮动元素不重叠(自适应两栏布局)

    <style>
      .father {
        background-color: red;
        border: 3px solid red;
        overflow: hidden;
      }


      .child1 {
        width: 200px;
        height: 200px;
        background-color: green;

        float: left;
        margin-right: 20px;
      }

      .child2 {
        height: 100px;
        background-color: blue;
      }
    </style>

image.png

解决办法:给child2创建BFC

      .child2 {
        height: 100px;
        background-color: blue;

        overflow: hidden;
      }

image.png

利用这个特性就可以做自适应两栏布局,左边栏浮动,右边栏创建BFC

3、解决外边距折叠

块级盒子的 上下外边距 有时会合并(折叠)为单个边距,其大小为两个边距中的最大值(或如果它们相等,则仅为其中一个),这种行为称为外边距折叠。注意:有设定浮动和绝对定位的元素不会发生外边距折叠。

  • 兄弟元素上下外边距折叠:
 <body>
     <div class="child1"></div>
     <div class="child2"></div>
 </body>
   <style>
     * {
       margin: 0;
       background-color: rgb(230, 224, 224);
     }

     .child1 {
       width: 100px;
       height: 100px;
       background-color: green;

       margin-bottom: 20px;
     }

     .child2 {
       width: 100px;
       height: 100px;
       background-color: blue;

       margin-top: 20px;
     }
   </style>

  ~~ image.png

    ~~~~给child1或者child2包一层,创建BFC就可以防止折叠

<body>
   <div class="child1"></div>
   <div class="child2-wrapper">
     <div class="child2"></div>
   </div>
</body>
 .child2-wrapper {
       overflow: hidden;
  }

  ~~ image.png

  • 父子元素上下边距折叠

  ~~ 如果父级没有设置border、padding没有行级(inline)内容没有创建BFC,那它子元素则会出现margin-top上边距的折叠,重叠部分最终会溢出到父代元素的外面。如果还没有设置height、min-height,那子元素的margin-bottom下边距也会如此

  <body>
    <div class="child2-wrapper">
      <div class="child2"></div>
    </div>
    <div class="child1"></div>
  </body>
  <style>
      * {
        margin: 0;
        background-color: rgb(238, 193, 193);
      }

      .child2 {
        width: 100px;
        height: 100px;
        background-color: blue;

        margin-top: 20px;
        margin-bottom: 20px;
      }

      .child2-wrapper {
        background-color: red;
      }

      .child1 {
        background-color: green;
        height: 100px;
      }
    </style>

image.png

解决办法:给父级创建BFC

      .child2-wrapper {
        background-color: red;

        overflow: hidden;
      }

image.png

二、flex

flex属性是下面3个CSS 属性的简写:

  • flex-grow:负值无效,默认0,不放大,该值决定在 flex 容器中分配剩余空间的相对比例。
  • flex-shrink:负值无效,默认1,宽度不够又不换行会收缩,决定flex 元素在默认宽度之和大于容器的时候收缩的大小。
  • flex-basis:可以是关键字"auto"等关键字,10px、10em、0等length值,也可以是百分比,不能是负数。默认auto,按照其原本大小显示
    • 同时设置flex-basis和width,flex-basis(除auto)优先级更高

    • 设置关键字,基于flex 的元素的内容自动调整大小

flex语法规则:

image.png

1、flex:initial = flex:0 1 auto

flex默认值。元素会根据自身宽高(自适应内容)设置尺寸。容器空间不足,会缩小,容器有剩余空间不会增长

  <body>
    <div class="father">
      <div class="child child1">子child1</div>
      <div class="child child2">子child2子child2</div>
      <div class="child child3">子child3子child3子child3</div>
    </div>
  </body>
<style>
      .father {
        display: flex;
        border: 2px solid #ff00ee;
      }

      .child {
        color: #fff;
      }

      .child1 {
        background-color: green;
      }

      .child2 {
        background-color: blue;
      }

      .child3 {
        background-color: red;
      }
    </style>

image.png

  .father {
        display: flex;
        border: 2px solid #ff00ee;
        width:100px
      }

image.png

2、flex:0= flex:0 1 0%

不会增大,会收缩,flex-basis属性值是0%,表示基础尺寸是0,无论有无剩余空间 ,因此设置flex:0的元素尺寸 表现为 最小内容宽度

  .child {
        color: #fff;
        flex: 0
   }
image.png image.png

3、flex:none = flex:0 0 auto

不会增大,也不会收缩,元素的尺寸没有弹性变化,flex-basis属性值是auto,基础尺寸由内容决定,元素最终尺寸通常表现为 最大内容宽度

  .father {
        width:100px
      }
      
  .child {
        flex: 0
   }

image.png

image.png

4、flex:1 = flex:1 1 0%

元素尺寸可以增大,也可以缩小,但是剩余空间不足,元素尺寸会 优先最小化内容尺寸

 .child {
        flex: 1
   }

image.png

5、flex:auto = flex:1 1 auto

元素尺寸可以增大,也可以缩小,但是剩余空间不足,元素尺寸会 优先最大化内容尺寸

 .child {
        flex: auto
   }

image.png

参考

张鑫旭《CSS新世界》