BFC与布局

一.BFC

1.1 定义

BFC-Block Formating Context(块级格式化上下文)

  • 内部的Box会在垂直方向上一个接一个的放置
  • 同一个BFC的两个相邻Box的margin会发生重叠
  • 计算BFC的高度时,浮动子元素也参与计算
  • BFC的区域不会与float box重叠。
  • BFC是一个完全独立的空间,让空间里的子元素不会影响到外面的布局

当BFC外部存在浮动时,它不应该影响BFC内部Box的布局,BFC会通过变窄(如果没有设置宽度的话),而不与浮动有重叠

当BFC内部有浮动时,为了不影响外部元素的布局,BFC计算高度时会包括浮动的高度。 避免margin重叠也是这样的一个道理。  

1.2 触发原理

body

float:left/right

position:fixed/absolute

display:inline-block/table-cell/fixed

overfolw不为visible

1.3 BFC解决的问题

1.3.1 margin合并问题

 <div class="box1"></div>
 <div class="box2"></div>
复制代码
 div{
        width:100px;
        height:100px;
      }
      .box1{
        background-color: red;
        border:1px solid blue;
        padding:10px;
        margin-bottom:30px;
      }
      .box2{
        background-color: green;
        border:1px solid blue;
        padding:10px;
        margin-top:20px;
      }
复制代码

image.png

两个相邻的盒子在垂直方向上的margin值出现了合并状态,合并为两者margin较大的那个值,并且使用border或者padding是无法阻止这一现象的。

原因:Box垂直方向的距离由margin决定。属于同一个BFC(上例中是body根元素的BFC)的两个相邻Box的margin会发生重叠

 <div class="container">
      <div class="box1"></div>
    </div>
    <div class="box2"></div>
复制代码
 .box1{
        background-color: red;
        margin-bottom:130px;
        width:100px;
        height:100px;
      }
      .box2{
        background-color: green;
        margin-top:120px;
        width:100px;
        height:100px;
      }
      .container{
        overflow: hidden;
      }
复制代码

解决办法就是让.box1作为新BFC元素.container的子元素让其于body这个BFC元素的子元素.box2处于不同的BFC中,那么就可以解决margin合并的问题

 <div class="container">
      <div class="box1"></div>
    </div>
复制代码
.box1{
    background-color: red;
    margin-top:150px;
    width:100px;
    height:100px;
  }
  .container{
    width:200px;
    height:200px;
    margin-top:100px;
    background-color: green;
  }
复制代码

image.png

当父元素有margin值且子元素也有margin值的时候,取两者的最大值进行合并,并且还存在另一个问题就是为什么子元素的margin不是相对父元素的呢,这就涉及到margin-top塌陷的问题

这是由于此时父子盒子都处于body这个BFC之中,三者属于同一个BFC,那么一开始body也是有外边距的,所以会先和父盒子的100进行合并,其次在与子盒子进行合并就形成了最后的150px;

.box1{
    background-color: red;
    margin-top:150px;
    width:100px;
    height:100px;
  }
  .container{
    width:200px;
    height:200px;
    margin-top:100px;
    background-color: green;
    overflow: hidden;
  }
  body{
    display: flex;
  }
复制代码

让父盒子形成一个新的BFC,那么与body这个BFC元素就不是同一个,则margin不会合并,那么就是108px。其次由于创建了BFC的元素不会和它的子元素发生外边距叠加。

image.png

1.3.2 margin-top坍塌问题

<div class="container">
      <div class="box"></div>
</div>
复制代码
.container{
      width:500px;
      height:500px;
      background-color: blue;
      padding-top:10px;
      /* border:1px solid red; */
    }
    .box{
      width:100px;
      height:100px;
      background-color: green;
      margin-top:50px;
    }
复制代码

image.png

当父盒子有border-top或者有padding-top属性时,子盒子与父盒子不处于毗邻状态,则不会发生margin-top塌陷问题

<div class="container">
      <div class="box"></div>
</div>
复制代码
.container{
      width:500px;
      height:500px;
      background-color: blue;
    }
    .box{
      width:100px;
      height:100px;
      background-color: green;
      margin-top:50px;
    }
复制代码

image.png

如上述情况就会发生marin-top塌陷问题,指子元素设置了margin-top值但是它不相对父盒子发生位移,而带着父盒子于上一个外层元素发生位移

<div class="container">
      <div class="box"></div>
</div>
复制代码
.container{
      width:500px;
      height:500px;
      /* overflow:hidden; */
      /* position: absolute; */
      position:fixed;
      background-color: blue;
    }
    .box{
      width:100px;
      height:100px;
      background-color: green;
      margin-top:50px;
    }
复制代码

触发父盒子的BFC来解决这一问题

1.3.3 高度坍塌问题(float引发的高度坍塌问题)

 <div class="box">
      <div class="box1"></div>
      <div class="box2"></div>
    </div>
复制代码
 .box{
      width:200px;
      border:2px solid red;
    }
    .box1{
      float:left;
      width: 100px;
      height:100px;
      background-color: orange;
    }
    .box2{
      float:left;
      width: 100px;
      height:100px;
      background-color: green;
    }
复制代码

image.png

 .box{
      width:200px;
      border:2px solid red;
      /* float:left ; */
      overflow:hidden;
    }
    .box1{
      float:left;
      width: 100px;
      height:100px;
      background-color: orange;
    }
    .box2{
      float:left;
      width: 100px;
      height:100px;
      background-color: green;
    }
复制代码

image.png

触发BFC来满足BFC规则中的计算BFC的高度时,浮动元素也参与计算

1.3.4 环绕问题(float引发的环绕问题)

 <div class="box"></div>
  <div class="box1">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Praesentium cupiditate veniam ratione dicta eaque dolore ullam, minima at, maiores veritatis expedita repudiandae rem modi odit ab molestias, eveniet magni qui!</div>
复制代码
 .box{
      width:100px;
      height: 100px;
      float:left;
      background-color: #000;
    }
    .box1{
      /* float: left; */
      width:200px;
      height:200px;
      background-color: orange;
    }
复制代码

image.png

由于第一个元素浮动了脱离了文档流,而第二个块级元素识别不出浮动元素的位置,所以会覆盖上去。

.box{
      width:100px;
      height: 100px;
      float:left;
      background-color: #000;
    }
    .box1{
      float: left;
      width:200px;
      height:200px;
      background-color: orange;
    }
复制代码

image.png

触发BFC根据BFC规则BFC的区域不会与float box重叠可以防止覆盖的现象

参考文档

github.com/zuopf769/no…

二.浮动

2.1 浮动

float设计之初是为了实现文字环绕的效果,但是带来的是破坏了正常的文档流,但是其不会覆盖掉之前的文档流。毕竟浮动的元素对前面已经布局好的元素并不会带来影响,影响的是后续的元素。

<div class="container">
   <div class="box1"></div>
</div>
<div class="content">wenzi</div>
复制代码
 .container{
      width:200px;
      border:1px solid red;
    }
    .box1{
      width:100px;
      height:100px;
      background-color: green;
      float: left;
    }
    .content{
      width:200px;
      height:200px;
      background-color: blue;
    }
复制代码

image.png

浮动的元素并没有覆盖掉文字

浮动带来的影响:

首先造成父元素高度的坍塌

其次因为高度坍塌从而影响后续元素的布局

2.2 清除浮动

2.2.1 触发BFC(BFC不会与float box重叠)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <title>Document</title>
    <link rel="stylesheet" type="text/css" href="" />
  </head>
  <style type="text/css">

    .box{
      width:200px;
      border:10px solid #000;
      overflow:hidden; 
      /* 清除浮动但是如果需要滚动条啥的需求怎么办呢 所以这种方法也不好 */
    }
    .box1{
      float: left;
      width:100px;
      height:100px;
      background-color: green;
    }
    .box2{
      float: left;
      width:100px;
      height:100px;
      background-color: orange;
    }
  </style>
  <body>  
    <div class="box">
      <div class="box1"></div>
      <div class="box2"></div>
    </div>
  </body>
</html>
复制代码

2.2.2 clear:both

    /*清除浮动的最佳方法*/
    ul::after,
    div::after{
      content: "";
      display:block;
      clear:both;
    }
复制代码

2.2.3 设置清除浮动的类

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <title>Document</title>
    <link rel="stylesheet" type="text/css" href="" />
  </head>
  <style type="text/css">
    .box{
      width:200px;
      border:10px solid #000;
    }
    .box1{
      float: left;
      width:100px;
      height:100px;
      background-color: green;
    }
    .box2{
      float: left;
      width:100px;
      height:100px;
      background-color: orange;
    }
    /*清除浮动的次品方法*/
    .fixclear{
      clear:both
    }
  </style>
  <body>  
    <div class="box">
      <div class="box1"></div>
      <div class="box2"></div>
      <p class='fixclear'></p>
    </div>
  </body>
  <script src="" type="text/javascript" charset="utf-8"></script>
</html>
复制代码

三.绝对定位

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <title>Document</title>
    <link rel="stylesheet" type="text/css" href="" />
  </head>
  <style type="text/css">
    .container{
      width:200px;
      border:1px solid red;
    }
    .box1{
      width:100px;
      height:100px;
      background-color: green;
      position:absolute;
    }
    .content{
      width:200px;
      height:200px;
      background-color: blue;
    }
  
  </style>
  <body>
    <div class="container">
      <div class="box1"></div>
    </div>
    <div class="content">wenzi</div>
  </body>
  <script src="" type="text/javascript" charset="utf-8"></script>
</html>
复制代码

image.png

绝对定位的元素会覆盖。

四.三栏布局

4.1 flex实现

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <title>Document</title>
    <link rel="stylesheet" type="text/css" href="" />
  </head>
  <style type="text/css">
    #header,#footer{
    height: 50px;
    width: 100%;
    border: 1px solid;
    background-color: grey;
  }
  #content{
    display: flex;
    height:500px;
  }
  #left,#right{
    flex-basis: 200px;
    background-color: green;
  }
  #left{
    order:1
  }
  #middle{
    background-color: blue;
    flex-grow:1;
    order:2;
  }
  #right{
    order:3;
  }
  </style>
  <body>
    <div class="wrap">
      <div id="header">header</div>
      <div id="content">
        <div id="middle">middle</div>
        <div id="left">left</div>
        <div id="right">right</div>
      </div>
      <div id="footer">footer</div>
    </div>
  </body>
  <script src="" type="text/javascript" charset="utf-8"></script>
</html>
复制代码

4.2 圣杯布局(使用padding)

需要解决的问题:

  • margin-left:-100%怎么理解
  • 为什么需要定位
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <title>Document</title>
    <link rel="stylesheet" type="text/css" href="" />
  </head>
  <style type="text/css">
#header,#footer{
    height: 50px;
    width: 100%;
    border: 1px solid;
    background-color: grey;
}
#content{ 
  overflow: hidden;
  padding: 0px 200px;/*为了让文字显现出来*/
}
#left,#right{
  width: 200px;
  height: 200px;
  background-color:pink;
}
#middle{
  background-color: green;
  width: 100%;/*相对于内容的100%*/
  height: 200px;
  
}
#middle,#left,#right{
  float: left;

}
#left{
  /*这里怎么理解 margin-left是自身的左边界相对于上一个元素的右边界进行位移*/
  margin-left: -100%;
  /*当加入padding值后,由于margin-left是相对于内容的边界进行位移的,加入padding后边界就会产生变化 需要用定位来调整回来*/
  position: relative;
  left: -200px;
}
#right{
  margin-left: -200px;
  position: relative;
  left: 200px;
}

  
  </style>
  <body>
    <div class="wrap">
      <div id="header">header</div>
      <div id="content">
        <div id="middle">middle</div>
        <div id="left">left</div>
        <div id="right">right</div>
      </div>
      <div id="footer">footer</div>
    </div>
    
  </body>
  <script src="" type="text/javascript" charset="utf-8"></script>
</html>
复制代码

4.3 双飞翼布局(使用margin)

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
        <title>Document</title>
        <link rel="stylesheet" type="text/css" href="" />
    </head>
    <style type="text/css">
#header,#footer{
    height: 50px;
    width: 100%;
    border: 1px solid;
    background-color: grey;
}
#left,#right{
  width: 200px;
  height: 200px;
  background-color:pink;
}
#middle{
  background-color: green;
  width: 100%;
  height:200px;
  float: left;
}
#content{
  overflow: hidden;
}
#left{
  float: left;
  margin-left:-100%;
  /* 当margin-left 为父元素的-100%时,就会上移动一行。,行盒放置时,就会根据margin放置,( 其实应该是左边框距离上个兄弟元素的margin-right ) */

  /*相对于上一个浮动的盒子*/
  /*这里的margin占满了整行*/
}
#right{
  float: left;
  margin-left:-200px;  
  /* 相对left盒子margin */
}
.middle-inner{
  margin: 0 200px;  
  /* 因为现在middle的内容被left和right覆盖了,我们除了考虑设置外围content的padding之外,还可以考虑用margin把middle拉过来; */
}

    
    </style>
    <body>
        <div class="wrap">
            <div id="header">header</div>
            <div id="content">
              <div id="middle">
                <div class="middle-inner">middle</div>
              </div>
              <div id="left">left</div>
              <div id="right">right</div>
            </div>
            <div id="footer">footer</div>
          </div>
        
    </body>
    <script src="" type="text/javascript" charset="utf-8"></script>
</html>
复制代码

五.flex布局中涉及的缩放准则

5.1 flex-shrink

5.1.1 只有width

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <title>Document</title>
    <link rel="stylesheet" type="text/css" href="" />
  </head>
  <style type="text/css">
    * {
	padding: 0;
	margin: 0;
}
.container {
	width: 600px;
	height: 300px;
	display: flex;
}
.left {
	width: 500px;
	flex-shrink: 2;
	background: red;
}
.right {
	width: 400px;
	flex-shrink: 1;
	background: blue;
}

  </style>
  <body>
    <div class="container">
        <div class="left"></div>
        <div class="right"></div>
    </div>
  </body>
  <script src="" type="text/javascript" charset="utf-8"></script>
</html>
复制代码

.left与.right的宽度明显大于600,所以在设置flex-shrink之后,两者实际的宽度为多少呢?

  • 超出部分:500+400-600=300
  • 比例:5002 : 4001 = 5:2
  • 每块超出内容: 3005/7 3002/7
  • .left实际内容: 500 – 300*5/7 = 285.719
  • .right实际内容: 500 – 300*2/7 = 314.281

5.1.2 width+padding

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <title>Document</title>
    <link rel="stylesheet" type="text/css" href="" />
  </head>
  <style type="text/css">
   * {
	padding: 0;
	margin: 0;
}
.container {
	width: 600px;
	height: 300px;
	display: flex;
}
.left {
	width: 500px;
	flex-shrink: 2;
  padding:60px;
	background: red;
}
.right {
	width: 400px;
  padding:40px;
	flex-shrink: 1;
	background: blue;
}
  </style>
  <body>
    <div class="container">
        <div class="left"></div>
        <div class="right"></div>
    </div>
  </body>
  <script src="" type="text/javascript" charset="utf-8"></script>
</html>
复制代码
  • 超出部分:620+480-600 = 500
  • 比例:5002 : 4001 = 5:2
  • 每块超出内容: 5005/7 5002/7
  • .left实际内容: 620 – 500*5/7 = 262.857
  • .right实际内容: 480 – 500*2/7 = 337.143

5.1.3 width+padding+border

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <title>Document</title>
    <link rel="stylesheet" type="text/css" href="" />
  </head>
  <style type="text/css">
    * {
	padding: 0;
	margin: 0;
}
.container {
	width: 600px;
	height: 300px;
	display: flex;
}
.left {
	width: 500px;
	flex-shrink: 2;
  border:10px solid black;
  padding:60px;
	background: red;
}
.right {
	width: 400px;
  border:20px solid black;
  padding:40px;
	flex-shrink: 1;
	background: blue;
}

  </style>
  <body>
    <div class="container">
        <div class="left"></div>
        <div class="right"></div>
    </div>

  </body>
  <script src="" type="text/javascript" charset="utf-8"></script>
</html>
复制代码
  • 超出部分:640+520-600=560
  • 比例:5002 : 4001 = 5:2
  • 每块超出内容: 5605/7 5602/7
  • .left实际内容: 640 – 560*5/7 = 240
  • .right实际内容: 520 – 560*2/7 = 360

5.1.4 width+padding+border+margin

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <title>Document</title>
    <link rel="stylesheet" type="text/css" href="" />
  </head>
  <style type="text/css">
    * {
	padding: 0;
	margin: 0;
}
.container {
	width: 600px;
	height: 300px;
	display: flex;
}
.left {
	width: 500px;
	flex-shrink: 2;
  margin:0 10px;
  border:10px solid black;
  padding:60px;
	background: red;
}
.right {
	width: 400px;
  border:20px solid black;
  padding:40px;
  margin:0 20px;
	flex-shrink: 1;
	background: blue;
}

  </style>
  <body>
    <div class="container">
        <div class="left"></div>
        <div class="right"></div>
    </div>

  </body>
  <script src="" type="text/javascript" charset="utf-8"></script>
</html>
复制代码
  • 超出部分:660+560-600=620
  • 比例:5002 : 4001 = 5:2
  • 每块超出内容: 6205/7 6202/7
  • .left实际内容: 660 – 620*5/7 = 217.142
  • .right实际内容: 560 – 620*2/7 = 382.857

由上述四种情况总结得出 超出的部分必须由实际内容(width+border+padding+margin)来计算 而比列是由width来计算所以压缩的是真正内容的值

5.2 flex-grow

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <title>Document</title>
    <link rel="stylesheet" type="text/css" href="" />
  </head>
  <style type="text/css">
    * {
	padding: 0;
	margin: 0;
}
.container {
	width: 600px;
	height: 300px;
	display: flex;
}
.left {
	width: 100px;
	flex-grow: 3;      
	background: red;
}
.right {
	width: 200px;
  flex-grow:2;
	background: blue;
}

  </style>
  <body>
    <div class="container">
        <div class="left"></div>
        <div class="right"></div>
    </div>
  </body>
  <script src="" type="text/javascript" charset="utf-8"></script>
</html>
复制代码
  • 多余部分:600-100-200=300
  • 比例:3 : 2
  • 每块超出内容: 3003/5 3002/5
  • .left实际内容: 100 + 300*3/5 = 280
  • .right实际内容: 200 + 300*2/5 = 320
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <title>Document</title>
    <link rel="stylesheet" type="text/css" href="" />
  </head>
  <style type="text/css">
  /*真正占用空间等于 实际内容大小+padding+border+margin(margin到底算不算)*/
  /*剩余空间等于 实际内容大小减去最外层盒子容量(盒子有padding border咋办)*/
  /*实际分配的比例 仅仅是实际内容大小的比例*/
  /*grow和shrink的比例是按照内容大小为比列 然后根据剩余空间来分配的 */
  /*如果grow和shrink的值已经小于1了 就相当于其本身就是比例了*/
    * {
	padding: 0;
	margin: 0;
}
.container {
	width: 600px;
	height: 300px;
	display: flex;
}
.left {
	width: 100px;
	flex-grow: 0.3;      
	background: red;
}
.right {
	width: 200px;
  flex-grow:0.2;
	background: blue;
}

  </style>
  <body>
    <div class="container">
        <div class="left"></div>
        <div class="right"></div>
    </div>
  </body>
  <script src="" type="text/javascript" charset="utf-8"></script>
</html>
复制代码
  • left的宽度 100+300*0.3 = 190
  • righ的宽度 200+300*0.2 = 260
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享