Go to comments

HTML+CSS宝典 CSS进阶 块级格式上下文(BFC)

块级格式上下文(BFC)学习之后,将从更高的角度来看待常规流盒子的渲染,

而且这节课非常重要,会影响到我们做项目的时候,对整个网站的布局,布局的时候可能会用到 BFC 的知识。


BFC 也是在面试题中比较容易出现的知识,如果以后在面试的时候,或者与同事聊天的时候,

说把这个区域做一个 BFC,要知道意思是块级格式化上下文,我们简称 BFC。


一、什么是BFC

块级格式上下文全称 Block Formatting Context,简称 BFC


BFC是什么意思呢?

它是一块独立的渲染区域,它规规定了在该区域中,常规流块盒的布局。 

我们这节课实际就是认识这句话到底是什么意思,把这句话认识清楚了,这节课就学习完了。


1、先看这句话后面这一部分:它规规定了在该区域中,常规流块盒的布局 

这句的意思是,不是常规流的浮动、定位就不讨论了,这节课讨论的仅仅是常规流块盒的布局


回忆一下,常规流块盒的布局有哪些规则?

1. 常规流块盒在水平方向上,必须撑满包含块,

    常规流块盒的总宽度(内容 + 边框 + padding + margin)必须要刚好等于包含块的宽度

2. 常规流块盒在包含块的垂直方向上依次摆放,

    因为横向撑满了,没有空隙了,所以依次摆放

3. 常规流块盒若外边距(margin)无缝相邻,则进行外边距合并,

    只要中间没有隔 border、padding(padding指嵌套结构)之类的东西,外边距相邻就会合并

4. 常规流块盒的自动高度 和 摆放位置,无视浮动元素,

    就是无论盒子摆在哪里,还有高度自动的时候,都会无视浮动元素,当然更加无视定位元素,绝对定位、固定定位这些


上面这四点常规流块盒的布局,为什么要重新复习呢?

因为这些是块级格式化上下文所规定的,之前学习的时候说的是 视觉格式化模型 规定的,

应该这样说 视觉格式化模型 它里面包含了块级格式化上下文,而块级格式化上下文里面包含了这些具体的规则。


块级格式化上下文的范畴,它规定了在某一个区域中,常规流块盒的布局。


2、看这句话的前半部分,是这节课要讲的新知识,它是一块独立的渲染区域

就是说上面回顾的常规流块盒的布局,它是在某一个区域里面,这个区域就是块级格式化上下文,就是BFC创建的区域。


在这个区域里面常规流块盒是这样来排列的,

垂直排列、横向撑满、外边距合并、以及不计算浮动元素,这些规则都在一个区域中有效的,这个区域就叫做块级格式化上下文。


首先它是一个独立渲染区域,在这个区域里才会产生这些规则,这个渲染区域是怎么产生的呢?


二、如何创建BFC区域

BFC渲染区域由某个HTML元素创建,以下元素会在其内部创建BFC区域

1. 根元素,根元素就是HTMl元素,就意味着<html>元素创建的BFC区域,覆盖了网页中所有的元素

2. 浮动和绝对定位元素,在它的内部也会创建BFC区域

3. overflow属性不等于visible的块盒(overflow默认值是visible),overflow的值只要不是visible,这样的一个块盒也会在内部创建一个BFC区域

4. 还有display属性等于table,或者是表格的单元格,什么行块盒,这些也会在内部创建BFC,只不过上面三个是比较常见的


看下面这张图里面的元素形成了父子关系,A元素包含B元素、C元素包含D元素…

image.png


分析一下,这些元素处于谁创建的BFC区域?

首先是根元素(根元素是HTML)会创建一个BFC( 淡绿色表示整个覆盖的区域 ),根元素覆盖了网页中所有的区域

image.png


根元素会创建BFC,其它元素也会创建

A元素 是浮动元素也会创建BFC

C元素 是绝对定位的元素也会创建BFC(包括固定定位fixed)

G元素  overflow: hidden 也会创建BFC


因此页面上除了HTML元素,还有三个元素也创建了BFC

image.png


接下来思考一下,元素B处于谁创建的BFC区域里面?

元素B处在的区域,是由元素A创建的BFC所覆盖

image.png


所以总结起来

元素A、元素C、元素E、元素F、元素G,这些元素的他们所在区域,都处于根元素创建的BFC区域

元素B 所处位置,是元素A创建的BFC

元素D 所处位置,是元素C创建的BFC

元素H 所处位置,是元素G创建的BFC

也就是说这些元素,可能会处于不同的块级格式上下文里面。


我们上面学习了什么是渲染区域,它是怎么创建的,

下面学习什么是独立的渲染区域,独立就是分割开,里面的不影响外面的


三、BFC是独立的渲染区域

不同的BFC区域,它们进行渲染时互不干扰,创建BFC的元素,隔绝了它内部和外部的联系,内部的渲染不会影响到外部


具体来说有三个具体的规则

1. 创建BFC的元素,它的自动高度需要计算浮动元素

2. 创建BFC的元素,它的边框盒不会与浮动元素重叠

3. 创建BFC的元素,不会和它的子元素进行外边距合并


1、创建BFC的元素,它的自动高度需要计算浮动元素

常规流元素自动高度不会计算浮动元素,常规流看不见浮动的盒子,所以高度坍塌了,以前是给父元素加 .clearfix 样式清除浮动

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


现在学了BFC后还有一种做法,

创建BFC的元素,它的自动高度需要计算浮动元素,也就只要让父亲元素.container创建BFC就行了,就是创建了BFC盒子的高度要计算里面的浮动元素


这两种方法都会创建BFC,

position: absolute; 绝对定位的元素内部要创建BFC, 

float: left; 浮动元素内部也会创建BFC,

但是这两种方式都不太好,因为会改变盒子的排列方式,本来是常规流,把布局方式变了,会影响到布局


所以往往使用副作用最小的方式  overflow: hidden; ,overflow的值只要不是visible(可以改成scroll,也可以改成auto)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>创建BFC的元素,它的自动高度需要计算浮动元素</title>
<style>
  .container{
    background-color: lightblue;
    width: 600px;

    /* position: absolute; 绝对定位创建BFC */
    /* float: left;  浮动创建BFC */

    overflow: hidden; /* 可以改成scroll,也可以改成auto */
  }
  .item{
    float: left;
    width: 100px;
    height: 100px;
    margin: 10px;
    background-color: #008c8c;
  }
</style>
</head>
<body>

  <div class="container">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
  </div>

</body>
</html>

overflow:scroll 或 overflow:auto 还是会有副作用,可能会出现滚动条,副作用最小的方式是溢出隐藏 overflow:hidden


有些网站为了解决高度坍塌,可能没有使用清除法浮动的方式,使用了 overflow: hidden;  的方式

.clearfix{
  overflow: hidden;
}

不过如果仅仅是解决高度坍塌,清除浮动的方式是副作用是最小的,建议使用清楚浮动,因为有些元素就是要不在包含块内的。


2、创建BFC的元素,它的边框盒不会与浮动元素重叠

下面代码中两个元素应该怎样排列?

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
  .float{
    width:100px;
    height:100px;
    margin:10px;
    background-color: red;
    float: left;
  }
  .container{
    height: 200px;
    background-color: #008c8c;
  }
</style>
</head>
<body>

  <div class="float"></div>
  <div class="container"></div>

</body>
</html>

常规流元素摆放的时候,看不到浮动元素,它只看得到常规流,所以完全无视浮动元素在哪!


但是一旦让.container 元素内部创建BFC,

设置  overflow: hidden  创建了BFC之后,因为BFC里面的区域是一块独立渲染区域,一定不跟其它其它元素相互干扰

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>创建BFC的元素,它的边框盒不会与浮动元素重叠</title>
<style>
  .float{
    width:100px;
    height:100px;
    margin:10px;
    background-color: red;
    float: left;
  }
  .container{
    height: 200px;
    background-color: #008c8c;
    overflow: hidden; /* 创建BFC */
  }
</style>
</head>
<body>

  <div class="float"></div>
  <div class="container"></div>

</body>
</html>

所以这个时候.container元素排列的时候,一定会避开浮动元素


实际上浏览器给.container元素设置了一个margin-left,避开了浮动元素,

所以现在给.container元素设置margin-left没有效果


如果要设置这两个元素的距离,要设置.float浮动盒子的 margin-right 属性

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>创建BFC的元素,它的边框盒不会与浮动元素重叠</title>
<style>
  .float{
    width:100px;
    height:100px;
    margin:10px;
    background-color: red;
    float: left;
    margin-right:100px; /* 设置浮动盒子margin-right */
  }
  .container{
    height: 200px;
    background-color: #008c8c;
    overflow: hidden; /* 创建BFC */
  }
</style>
</head>
<body>

  <div class="float"></div>
  <div class="container"></div>

</body>
</html>

margin属性也是盒子的一部分,为了避开浮动元素,蓝色的盒子位置只能向右边移动了


这个现象对我们布局帮助很大,有时候我们可以把左边栏的宽度固定,然后另外一部分自动适应


3、 创建BFC的元素,不会和它的子元素进行外边距合并

实际上还可以换一个说法:

处在不同BFC中的元素,他们的外边距是不可能合并的,只有在同一个BFC里面的元素,外边距才能合并。


看例子

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
  .container{
    height: 100px;
    background-color: #008c8c;
    margin-top:30px;
  }
  .child{
    height:50px;
    margin:30px;
    background-color: red;
  }
</style>
</head>
<body>

  <div class="container">
    <div class="child"></div>
  </div>

</body>
</html>

.child元素的上外边距 和  .container元素的上外边距合并了


但是给外面的.container元素加上 overflow: hidden,上外边距就不合并了

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
  .container{
    height:100px;
    background-color:#008c8c;
    margin-top:30px;
    overflow:hidden; /* 创建BFC */
  }
  .child{
    height:50px;
    margin:30px;
    background-color: red;
  }
</style>
</head>
<body>

  <div class="container">
    <div class="child"></div>
  </div>

</body>
</html>


1. .container 元素处于根元素 HTML 创建的 BFC 里面,

2. 而 .child 元素处于,.container 元素创建的 BFC 里面,

3. 他们的外边距尽管相邻,但是由于这两个元素,不是处于同一个 BFC,它们之间的渲染是不互相干扰的,因此他们的外边距是不能合并的


4、创建BFC的元素,它的边框盒不会与浮动元素重叠

这句话,边框盒不会与浮动元素重叠,只是浮动元素了,

绝对定位的元素和固定定位的元素就不考虑,绝对定位的元素 和 固定定位的元素是完全脱离常规流的,


浮动还和常规流之间还有一定联系,比如行盒排列的时候要避开浮动

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>不会与浮动元素重叠</title>
<style>
  .container{
    overflow: hidden;
    background-color: #008c8c;
  }
  .item{
    float: left;
    margin: 20px;
    width: 200px;
    height: 200px;
    background-color: red;
  }
</style>
</head>
<body>

  <div class="container">
    <div class="item"></div>
  </div>

</body>
</html>

因为父级元素是BFC,所以计算浮动元素的高度


如果子元素不是浮动元素,是绝对定位元素,就脱离常规流了,父级元素就坍塌了

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
  .container{
    overflow: hidden;
    background-color: #008c8c;
  }
  .item{
    /* float: left; */
    position: absolute;
    margin: 20px;
    width: 200px;
    height: 200px;
    background-color: red;
  }
</style>
</head>
<body>

  <div class="container">
    <div class="item"></div>
  </div>

</body>
</html>


总结,

绝对定位元素和固定定位元素,不可能计算它的高度,完全无视,因为它彻底脱离了常规流


 display: flow-root 



Leave a comment 0 Comments.

Leave a Reply

换一张