面试基础之 BFC
大家好,第一次编写前端相关的技术文章,写的不好大佬们可以给点建议,
BFC算是在面试中比较常见的话题了,但很多人还是没有搞清楚BFC是什么?以及如何创建BFC?等系列问题,接下来我们一起来探讨一下BFC😊😊😊
BFC 概念
首先,我们先给出 FBC 的定义。
BFC(Block Formatting Contexts)是块格式化上下文,是CSS在渲染过程中生成块级盒子的一个区域,你可以理解为,具有FBC特性的元素,块级盒子里面的元素不会影响外面的元素,
因此,我们必须先掌握盒子模型。
盒子模型
什么是盒子模型?
在 CSS 中,任何一个元素都可以看作是一个盒子,而一个盒子通常由四部分组成(由内到外):内容(content)、内边距(padding)、边框(border)和外边距(margin)。
在
CSS中,盒子模型一般分为两种:标准盒子模型和IE盒子模型,分别是W3C和IExplore制定的标准。
假设一个盒子的 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 特性的元素不会跟相邻元素重叠。
父元素和子元素重叠问题
父元素无 border、padding、overflow 时,子元素的 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都可以达到同样的效果,感兴趣的赶紧去试试吧⏱️
清除浮动
首先我们先搞清楚什么是浮动?才能对浮动带来的问题进行进一步的分析以及后续的解决方案。
什么是浮动?
概念
首先,浮动元素会脱离文档流,向左或者向右进行浮动,直到碰到下一个浮动元素或者父元素,这就是浮动元素。
浮动元素造成什么问题?
如下
代码如下:
<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即可。
清除浮动后的显示结果如下:
代码如下:
<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
标签法清除浮动
清除浮动后的显示结果如下:
代码如下:
<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>
清除浮动后的显示结果如下:
两栏布局
通常我们在设计两栏布局,你们是怎么做的呢?通过 flex 布局?确实, flex 布局确实挺方便的,这里,我介绍几种用于两栏布局的方案 🤗🤗🤗
使用 float + overflow 实现
显示结果如下:
是不是很轻松的实现了呢?🤗
代码如下:
<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
显示结果如下:
代码如下:
<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 布局(超强大)
显示结果如下:
代码如下:
<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 布局了 🤗🤗
显示结果如下:
代码如下:
<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 应用的场景,在这过程中,如果哪些地方写的不对,希望大佬们提提意见 🤗🤗🤗