阅读 193

JS 系列之 BFC

JS 系列之 BFC

大家好,我是戴锐宁,第一次编写前端相关的技术文章,写的不好大佬们可以给点建议,BFC 算是在面试中比较常见的话题了,但很多人还是没有搞清楚 BFC 是什么?以及如何创建 BFC?等系列问题,接下来我们一起来探讨一下 BFC 😊😊😊

BFC 概念

首先,我们先给出 FBC 的定义。

BFC(Block Formatting Contexts)是块格式化上下文,是 CSS 在渲染过程中生成块级盒子的一个区域,你可以理解为,具有 FBC 特性的元素,块级盒子里面的元素不会影响外面的元素,

因此,我们必须先掌握盒子模型。

盒子模型

什么是盒子模型?

CSS 中,任何一个元素都可以看作是一个盒子,而一个盒子通常由四部分组成(由内到外):内容(content)、内边距(padding)、边框(border)和外边距(margin)。

CSS 中,盒子模型一般分为两种:标准盒子模型和IE盒子模型,分别是 W3CIExplore 制定的标准。

假设一个盒子的 CSS 样式为如下:

.box {
  width: 600px;
  height: 300px;
  padding: 20px;
  border: 2px solid pink;
  margin: 50px;
}
复制代码

标准盒子模型

标准盒子模型认为:盒子的实际尺寸大小 = 内容(设置的宽高)+ 内边距(padding) + 边框(border

所以 .box 元素内容的宽度就为 600px,而盒子实际的宽度则是 width + padding-left + padding-right + border-left-width + border-right-width = 600 + 20 + 20 + 2 + 2 = 644。

IE盒子模型

IE盒子模型认为:盒子的实际尺寸大小 = 内容 + 内边距(padding) + 边框(border)= 设置的宽高

所以 .box 元素内容的宽度就为 600px,而内容实际的宽度则是 width - padding-left - padding-right - border-left-width - border-right-width = 600 - 20 - 20 - 2 - 2 = 556。而盒子的实际宽度就是设置的宽高,也就是盒子的实际宽度 = 设置的宽高(width)。

现在基本上都是使用 W3C 制定的标准的盒子模型,只有一些低版本的浏览器才使用 IExplore 制定的IE盒子模型

如果我们需要的不想改变盒子大小,不想在设置 padding 或者 border 的时候,盒子就会撑开,而就是想保持盒子大小,那应该怎么做呢?

在 CSS3 中新增了一个属性 box-sizing,允许开发人员来指定盒子使用什么标准,它有 2 个值:

  • content-box:用来指明该盒子模型是标准盒子模型(也是默认值)
  • border-box:用来指明该盒子模型是IE盒子模型

再次声明:
标准盒子模型尺寸 = width + padding + border;
IE盒子模型尺寸 = content + padding + border = width

BFC 原理是什么?

原理:

  • 具备 BFC 特性的元素不会跟浮动元素进行重叠
  • 具备 BFC 特性的区域不会跟相邻元素进行重叠
  • 具备 BFC 特性的区域在计算高度时会计算子元素浮动元素的高度(不会出现父元素高度坍塌问题)
  • 具备 BFC 特性的区域会生成块级作用域,不会影响外面的元素

BFC 如何创建?

创建规则:

  • html 根元素就是一个 BFC
  • display 的值为 inline-block、table-cell、table-caption、flex、grid、inline-grid 的元素
  • position 的值为 absolute 和 fixed 的元素
  • float 的值不为 none 的元素
  • overflow 的值不为 visible

BFC 的应用场景有哪些?

应用场景

  • 消除上下边距重叠
  • 清除浮动
  • 两栏布局,左边固定、右边自适应

下面对这几个场景分别介绍

外边距重叠问题

概念

外边距重叠是指两个或多个盒子(可能相邻也可能嵌套)的相邻边界(其间没有任何非空内容、补白、边框)重合在一起而形成一个单一边界。

外边距重叠问题分为两种:

  • 上下边距重叠问题
  • 父元素和子元素重叠问题

上下边距重叠问题

也就是一个设置 margin-bottom 和一个 margin-top 而出现了外边距重叠的问题

如下:

<style>
  .box1{
    width: 100px;
    height: 100px;
    background: yellow;
    margin-bottom: 50px;
    border: 1px solid pink;
  }
  .box2{
    width:50px;
    height: 50px;
    background: yellow;
    margin-top: 80px;
    border: 1px solid pink;
  }
</style>
<body>
  <div class="box1"></div>
  <div class="box2"></div>
</body>
复制代码

显示效果如下:

外边距重叠的计算方式

计算方式

  • 全部都为正值,取最大者;
  • 不全是正值,则都取绝对值,然后用正值的最大值减去绝对值的最大值;
  • 没有正值,则都取绝对值,然后用 0 减去最大值。

解决的办法

解决的办法

  • 底部元素设置为浮动 float: left
  • 底部元素的 position 的值为 absolute/fixed
  • 在设置 margin-top/bottom 值时统一设置上或下(避免方法)

如下:

<style>
  .box1{
    width: 100px;
    height: 100px;
    background: yellow;
    margin-bottom: 50px;
    border: 1px solid pink;
  }
  .box2{
    width:50px;
    height: 50px;
    background: yellow;
    margin-top: 80px;
+   float: left;
    border: 1px solid pink;
  }
</style>
<body>
  <div class="box1"></div>
  <div class="box2"></div>
</body>
复制代码

显示效果如下:

理解

其实就是利用了 BFC 特性的原理,具备 BFC 特性的元素不会跟相邻元素重叠。

父元素和子元素重叠问题

父元素无 borderpaddingoverflow 时,子元素的 margin-top/bottom 会与父元素的 margin 产生重叠问题。

如下:

<style>
#parent{
  width: 300px;
  height: 300px;
  margin-top: 20px;
  background: #27aa4b;
}
#box1{
  width: 100px;
  height: 100px;
  background: #6e30b4;
  margin: 100px 100px;
}
</style>
<body>
  <div id="parent">
    <div id="box1">
      我是box1
    </div>
  </div>
</body>
复制代码

显示效果如下:

理解

可以发现,在图片上面出现了很大一部分白色的区域,这个就是造成父子元素高度坍塌的问题

解决的办法

解决的办法如下:

  • 外层元素添加 padding;
  • 外层元素 overflow: hidden;
  • 外层元素透明边框 border: 1px solid transparent;
  • 内层元素绝对定位 position: absolute:
  • 内层元素加 float: left; 或 display: inline-block;

如下:

<style>
#parent {
  width: 300px;
  height: 300px;
  margin-top: 20px;
  background: #27aa4b;
  overflow: hidden;
}
#box1 {
  width: 100px;
  height: 100px;
  background: #6e30b4;
  margin: 100px 100px;
}
</style>
<body>
  <div id="parent">
    <div id="box1">
      我是box1
    </div>
  </div>
</body>
复制代码

显示效果如下:

理解

通过设置父元素 overflow: hidden 后,可以就正常显示,这是因为设置了 BFC 的缘故,也可以给父元素增加一个透明边框或增加 padding 都可以达到同样的效果,感兴趣的赶紧去试试吧⏱️

清除浮动

首先我们先搞清楚什么是浮动?才能对浮动带来的问题进行进一步的分析以及后续的解决方案。

什么是浮动?

概念

首先,浮动元素会脱离文档流,向左或者向右进行浮动,直到碰到下一个浮动元素或者父元素,这就是浮动元素。

浮动元素造成什么问题?

如下

box3.png

代码如下:

<style>
  #parent{
    background: #27aa4b;
    margin-bottom: 10px;
  }
  #box1{
    width: 100px;
    height: 80px;
    margin-bottom: 10px;
    background: #6e30b4;
    float: left;
  }
  #box2 {
    width: 100px;
    height: 100px;
    background: #3086b4;
    float: left;
  }
</style>
<body>
  <div id="parent">
    <div id="box1"></div>
    <div id="box2"></div>
  </div>
</body>
复制代码

理解

因为浮动元素并不会占据文档流中的位置,所以如果一个父元素下边都是浮动元素的话,那么父元素就无法被负浮动元素都撑开,这样一来父元素就丢失了高度,这就是所谓浮动元素造成高度坍塌的问题,所以必须要清除浮动,让父元素恢复高度。

如何清除浮动?

对于清除浮动方法有很多,我们最常用的清除浮动的方式就是利用 BFC 特性,其原理如下:

BFC 清除浮动

原理

计算 BFC 的高度时,浮动元素的高度也参与计算,所以只需要触发父元素的 BFC 即可。

清除浮动后的显示结果如下:

box3.png

代码如下:

<style>
  #parent{
    background: #27aa4b;
    margin-bottom: 10px;
+   overflow: hidden;
  }
  #box1{
    width: 100px;
    height: 80px;
    margin-bottom: 10px;
    background: #6e30b4;
    float: left;
  }
  #box2 {
    width: 100px;
    height: 100px;
    background: #3086b4;
    float: left;
  }
</style>
<body>
  <div id="parent">
    <div id="box1"></div>
    <div id="box2"></div>
  </div>
</body>
复制代码

理解

使用 BFC 清除浮动后就恢复高度了,显示也正常了

也可以给父元素增加其他的 BFC 来实现清除浮动的效果

  • float 值为 left | right
  •  overflow 值为 hidden | auto | scorll
  •  display 值为 table-cell | table-caption | inline-block | flex | grid
  •  position 值为 absolute | fixed

标签法清除浮动

清除浮动后的显示结果如下:

box3.png

代码如下:

<style>
  #parent {
    background: #27aa4b;
    margin-bottom: 10px;
  }
  #box1 {
    width: 100px;
    height: 80px;
    margin-bottom: 10px;
    background: #6e30b4;
    float: left;
  }
  #box2 {
    width: 100px;
    height: 100px;
    background: #3086b4;
    float: left;
  }
</style>
<body>
  <div id="parent">
    <div id="box1"></div>
    <div id="box2"></div>
    <div style="clear: both"></div>
  </div>
</body>
复制代码

理解

通过在最后一个元素增加一个标签,并设置 clear: both 同样能达到相同的效果

伪类清除浮动(最佳实践)

代码如下:

/**现代浏览器clearfix方案,不支持IE6/7*/
.clearfix:after {
  display: table;
  content: " ";
  clear: both;
}

/**全浏览器通用的clearfix方案*/
/**引入了zoom以支持IE6/7*/
.clearfix:after {
  display: table;
  content: " ";
  clear: both;
}
.clearfix{
    zoom: 1;
}

/**全浏览器通用的clearfix方案【推荐】*/
/**引入了zoom以支持IE6/7*/
/**同时加入:before以解决现代浏览器上边距折叠的问题*/
.clearfix:before,
.clearfix:after {
    display: table;
    content: " ";
}
.clearfix:after {
    clear: both;
}
.clearfix{
    zoom: 1;
}
复制代码

实践一下

<style>
  #parent:after {
    display: table;
    content: " ";
    clear: both;
  }
  #parent {
    background: #27aa4b;
    margin-bottom: 10px;
  }
  #box1 {
    width: 100px;
    height: 80px;
    margin-bottom: 10px;
    background: #6e30b4;
    float: left;
  }
  #box2 {
    width: 100px;
    height: 100px;
    background: #3086b4;
    float: left;
  }
</style>
<body>
  <div id="parent">
    <div id="box1"></div>
    <div id="box2"></div>
  </div>
</body>
复制代码

清除浮动后的显示结果如下:

box3.png

两栏布局

通常我们在设计两栏布局,你们是怎么做的呢?通过 flex 布局?确实, flex 布局确实挺方便的,这里,我介绍几种用于两栏布局的方案 🤗🤗🤗

使用 float + overflow 实现

显示结果如下:

box1.png

是不是很轻松的实现了呢?🤗

代码如下:

<style>
  .box1 {
    width: 200px;
    height: 500px;
    background: pink;
    float: left;
  }
  .box2 {
    height: 500px;
    background: chocolate;
    overflow: hidden;
  }
</style>
<body>
  <div class="box1"></div>
  <div class="box2"></div>
</body>
复制代码

使用 float + margin-left

显示结果如下:

box1.png

代码如下:

<style>
  .box1 {
    width: 200px;
    height: 500px;
    background: pink;
    float: left;
  }
  .box2 {
    height: 500px;
    background: chocolate;
    margin-left: 200px;
  }
</style>
<body>
  <div class="box1"></div>
  <div class="box2"></div>
</body>
复制代码

同样可以实现相同的效果

使用 grid 布局(超强大)

显示结果如下:

box1.png

代码如下:

<style>
  .parent {
    width: 100%;
    height: 500px;
    display: grid;
    grid-template-columns: 200px auto;  /*设定2列就ok了,auto换成1fr也行*/
  }
  .box1 {
    width: 200px;
    height: 500px;
    background: pink;
  }
  .box2 {
    background: chocolate;
    height: 500px;
  }
</style>
<body>
  <div class="parent">
    <div class="box1"></div>
    <div class="box2">123</div>
  </div>
</body>
复制代码

Flex 布局

终于来到我们最爱的 Flex 布局了 🤗🤗

显示结果如下:

box1.png

代码如下:

<style>
  .parent {
    width: 100%;
    height: 500px;
    display: flex;
  }
  .box1 {
    width: 200px;
    height: 500px;
    background: pink;
  }
  .box2 {
    background: chocolate;
    height: 500px;
    flex: 1;
  }
</style>
<body>
  <div class="parent">
    <div class="box1"></div>
    <div class="box2">123</div>
  </div>
</body>
复制代码

其实,flex 也是我最喜欢的布局方式之一 🤤🤤

总结

至此,终于把 BFC 相关的知识点总结全部梳理了一遍了,主要还是将自己所学的巩固了一下,以及将他们串联在一起,通过一个 BFC 引出盒子模型、外边距塌陷、浮动造成的问题,以及 BFC 应用的场景,在这过程中,如果哪些地方写的不对,希望大佬们提提意见 🤗🤗🤗

文章分类
前端
文章标签