Open maicFir opened 2 years ago
BFC(Block Formatting Context)俗称块级格式上下文,初次看到这词似乎有点不是很理解,通俗解释就是一个独立区域决定了内部元素的排放,以及内部元素与外部元素的相互作用关系
Block Formatting Context
正文开始...
俗称块级格式上下文,一块独立的区域决定了内部元素的位置排列,以及内部元素与外部元素的作用关系
我们先了解下BFC有什么特点
BFC
1、垂直方向,相邻BFC的块级元素会产生外边距合并
相邻BFC
2、BFC 包含浮动元素,浮动会触发新的 BFC 产生
3、已经确定的 BFC 区域不会与相邻 BFC 的浮动元素边距发生重合
针对以上几点我来具体深究一下 BFC 的特性到底有何区别,在什么样的场景下会比较触发BFC
新建一个index.html测试
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>BFC</title> <style> * { padding: 0; margin: 0; } .wrap-box { width: 300px; } .inner-box { width: 100px; height: 50px; } .inner-box:nth-of-type(2n + 1) { background-color: red; } </style> </head> <body> <div class="wrap-box"> <div class="inner-box">1</div> <div class="inner-box">2</div> <div class="inner-box">3</div> </div> </body> </html>
不出意外在wrap-box这个 BFC 中,内部元素垂直单行排列 这说明块级格式上下文,在wrap-box这个元素决定了内部的元素排放,因为子元素始终是被包裹起来的,因为是块级元素,所以单行排列。
wrap-box
接下来我们将子元素添加外边距margin:10px 0;
margin:10px 0
* { padding: 0; margin: 0; } .wrap-box { width: 300px; } .inner-box { width: 100px; height: 50px; margin: 10px 0; }
另外我们看下wrap-box的盒子模型 在子元素inner-box我们加了外边距margin,我们从已知的BFC特点知道相邻的BFC外边距会合并。
inner-box
margin
因为被包裹的inner-box是三个块级元素,在wrap-box内部来说,这三个内部div形成独立的BFC,所以相邻的1-2,2-3的外边距就合并了。
div
1-2,2-3
现在我有个需求,我不想让他们合并,我要破坏内部的三个 BFC 结构怎么办?
因此我需要将第二个inner-box改造成一个新的 BFC 结构
<div class="wrap-box"> <div class="inner-box">1</div> <div class="inner-box-2"> <div class="inner-box">2</div> </div> <div class="inner-box">3</div> </div>
注意我在第二个元素多加了一层结构 因此结构变成下面这样,主要看第三个图,我用虚线标出了表明第二元素已经被加了一层结构,貌似外边距还是会合并,这是为啥? 从新的结构我们可以知晓,相邻块级元素的BFC会使边距发生合并,以前的内部的 BFC 是123,现在新的 BFC 是143,2已经被4包裹独立出来了,在 2 内部的margin会作用到父级,从而作用到父级相邻的 BFC 结构。
相邻块级元素的BFC
123
143
2
4
我们继续在4上添加一个margin:10px 0,神奇的事情发生了,居然还是一样边距被合并了,具体看下代码
.wrap-box { width: 300px; } .inner-box { width: 100px; height: 50px; margin: 10px 0; overflow: hidden; } .inner-box:nth-of-type(2n + 1) { background-color: red; } .inner-box-2 { margin: 10px 0; }
你会发现居然在2的外层加了magrin,居然不会影响整个盒模型的高度。
magrin
因此你再细品那句话相邻块级格式上下文的上下边距会产生重叠,于是你恍然大悟,143是三个 BFC 结构,所以 4 设置margin自然就被重合了。
相邻块级格式上下文的上下边距会产生重叠
但是我要破坏这种相邻 BFC 结构,因此触发 BFC 结构的机会来了。我给inner-box-2加个样式,用overflow:hidden触发生成一个新的 BFC;
inner-box-2
overflow:hidden
现在就变成了这样了 没错,盒子模型高度变成了190了,中间的4外边距没有合并了。
190
由于在4不是虽然不是根元素,但是身上加了overflow:hidden触发4形成一个新的 BFC,那么触发 BFC 还有其他什么方式吗?
我们了解到除了overflow:hidden,还有以下几种方式 overflow: auto;display: flex; display: table;display: -webkit-box; float: left;
overflow: auto;display: flex; display: table;display: -webkit-box; float: left;
.inner-box-2 { margin: 10px 0; overflow: hidden; /* overflow: auto; */ /* display: flex; */ /* display: table; */ /* display: -webkit-box; */ /* float: left; */ }
当我们把inner-box-2设置为浮动后,边距就不会合并了。这也证实了相邻 BFC 与已经设置的浮动元素边距并不会合并,但inner-box-2与inner-box-1始终在一个大的BFC包裹着,而每一个自身元素又形成一个独立的BFC。 :::: code-group ::: code-group-item html
inner-box-1
<div class="wrap-box"> <div class="inner-box inner-box-1">1</div> <div class="inner-box inner-box-2">2</div> </div>
::: ::: code-group-item css
<style> *{ padding: 0; margin: 0; } .wrap-box { width: 300px; border: 1px solid #111; overflow: hidden; } .inner-box { width: 100px; height: 50px; margin: 10px 0; overflow: hidden; } .inner-box-2 { float: left; } .inner-box:nth-of-type(2n+1) { background-color: red; } .inner-box:nth-of-type(2n) { background-color: yellow; } </style>
::: ::::
我们知道相邻的 BFC 结构垂直方向外边距会合并,利用这点,我们实现九宫格布局 :::: code-group ::: code-group-item html
<div class="wrap-box"> <div class="inner-box">1</div> <div class="inner-box">2</div> <div class="inner-box">3</div> <div class="inner-box">4</div> <div class="inner-box">5</div> <div class="inner-box">6</div> <div class="inner-box">7</div> <div class="inner-box">8</div> <div class="inner-box">9</div> </div>
* { padding: 0; margin: 0; } .wrap-box { width: 300px; border: 1px solid #111; display: flex; flex-wrap: wrap; } .inner-box { width: 100px; height: 50px; margin: 10px 0; overflow: hidden; float: left; } .inner-box:nth-of-type(2n + 1) { background-color: red; } .inner-box:nth-of-type(2n) { background-color: yellow; }
::: :::: 注意我们给所有的子元素加了浮动,那么此时会造成父元素高度坍塌,因此父级元素必须要加上overflow:hidden或者设置display: inlie-block或者position: absolute;这样才可以导致父级元素不坍塌。
display: inlie-block
position: absolute
貌似456中间元素因为设置浮动破坏了BFC,所以我们需要给456设置特殊margin才行,于是乎你给 456 加一层 div,然后设置margin: -10px 0并且要设置左浮动 :::: code-group ::: code-group-item css
456
margin: -10px 0
左浮动
.item-2 { float: left; margin: -10px 0; }
::: ::: code-group-item html
<div class="wrap-box"> <div class="inner-box">1</div> <div class="inner-box">2</div> <div class="inner-box">3</div> <div class="item-2"> <div class="inner-box">4</div> <div class="inner-box">5</div> <div class="inner-box">6</div> </div> <div class="inner-box">7</div> <div class="inner-box">8</div> <div class="inner-box">9</div> </div>
::: :::: OK 已经可以了
此时我们这样改 dom 结构似乎有点不是很好,因为可能数据是从后端接口返回并不是写死的数据结构,因此我们再改下结构布局 :::: code-group ::: code-group-item html
<div class="wrap-box"> <div class="item"> <div class="inner-box">1</div> <div class="inner-box">2</div> <div class="inner-box">3</div> </div> <div class="item"> <div class="inner-box">4</div> <div class="inner-box">5</div> <div class="inner-box">6</div> </div> <div class="item"> <div class="inner-box">7</div> <div class="inner-box">8</div> <div class="inner-box">9</div> </div> </div>
* { padding: 0; margin: 0; } .wrap-box { width: 300px; border: 1px solid #111; overflow: hidden; } .inner-box { width: 100px; height: 50px; overflow: hidden; float: left; } .inner-box:nth-of-type(2n + 1) { background-color: red; } .inner-box:nth-of-type(2n) { background-color: yellow; } .item { margin: 10px 0; overflow: hidden; }
::: :::: 我们最初把margin作用在每个小元素下,现在我们利用BFC的特性,我们把margin作用在item上,因为三个item就是相邻垂直方向的 BFC 结构,边距会产生合并,也正是利用边距合并巧妙的解决了保持边距相等的问题。
item
具体可以看下效果 由于不同的布局方式,因此写出来的页面拓展性是完全不一样,拓展性强的布局方式,对于后期的维护是相当有益。因此不推荐第一种方式改结构,然后特殊设置456的父边距,虽然效果能达到一致,但是后期维护性与拓展性不高。
有时候左侧固定,右侧自适应这种页面结构时常会有,这种布局方案有哪些可以实现呢 :::: code-group ::: code-group-item html
<h1>左边固定,右边自适应,右边随着左边的宽度而自适应</h1> <div class="wrap-box"> <div class="slide-left">left</div> <div class="main">main</div> </div>
* { padding: 0; margin: 0; } .wrap-box { width: 300px; border: 1px solid #111; overflow: hidden; resize: horizontal; } .slide-left { width: 100px; height: 100px; background-color: red; } .main { height: 100px; background-color: yellow; }
::: :::: 此时发现页面不尽人意,肯定是下面这样的 但是当我们给slide-left设置float:left后,我们会发现,此时slide-left的文档流被破坏,main会紧贴着slide-left排列
slide-left
float:left
main
.slide-left { width: 100px; height: 100px; background-color: red; resize: horizontal; float: left; }
此时我们可以观察到main贴着slide-left,宽度就是父级的宽度
但实际上main是需要剩下的宽度,他需要根据左侧的slide-left的宽度而自适应 因此你可以,让main成为一个独立 BFC,我们需要设置它oveflow:hidden就行 那么此时就会变成 完整的 css 如下
oveflow:hidden
* { padding: 0; margin: 0; } .wrap-box { width: 300px; border: 1px solid #111; overflow: hidden; resize: horizontal; } .slide-left { width: 100px; height: 100px; background-color: red; float: left; } .main { height: 100px; background-color: yellow; overflow: hidden; }
OK,现在就实现了右侧根据左侧宽度的大小自适应了。 更多关于 BFC 可以参考MDN BFC
了解什么是 BFC,BFC 简称块级格式上下文,它是一块独立的区域影响子元素的排列,相邻区域的 BFC 边距会产生重合
触发 BFC 条件有,display: flex、display: inline-block、display:box,position:absolute,或者oveflow: hidden/auto,float:left;
display: flex
display: inline-block
display:box
position:absolute
oveflow: hidden/auto
利用 BFC 实现九宫布局,本质利用相邻 BFC 外边距合并
左侧固定,右侧自适应布局
本文 code example
正文开始...
BFC 是什么
俗称块级格式上下文,一块独立的区域决定了内部元素的位置排列,以及内部元素与外部元素的作用关系
BFC 特点
我们先了解下
BFC
有什么特点1、垂直方向,
相邻BFC
的块级元素会产生外边距合并2、BFC 包含浮动元素,浮动会触发新的 BFC 产生
3、已经确定的 BFC 区域不会与相邻 BFC 的浮动元素边距发生重合
针对以上几点我来具体深究一下 BFC 的特性到底有何区别,在什么样的场景下会比较触发
BFC
新建一个
index.html
测试不出意外在
wrap-box
这个 BFC 中,内部元素垂直单行排列 这说明块级格式上下文,在wrap-box
这个元素决定了内部的元素排放,因为子元素始终是被包裹起来的,因为是块级元素,所以单行排列。接下来我们将子元素添加外边距
margin:10px 0
;另外我们看下
wrap-box
的盒子模型 在子元素inner-box
我们加了外边距margin
,我们从已知的BFC
特点知道相邻的BFC
外边距会合并。因为被包裹的
inner-box
是三个块级元素,在wrap-box
内部来说,这三个内部div
形成独立的BFC
,所以相邻的1-2,2-3
的外边距就合并了。现在我有个需求,我不想让他们合并,我要破坏内部的三个 BFC 结构怎么办?
因此我需要将第二个
inner-box
改造成一个新的 BFC 结构注意我在第二个元素多加了一层结构 因此结构变成下面这样,主要看第三个图,我用虚线标出了表明第二元素已经被加了一层结构,貌似外边距还是会合并,这是为啥? 从新的结构我们可以知晓,
相邻块级元素的BFC
会使边距发生合并,以前的内部的 BFC 是123
,现在新的 BFC 是143
,2
已经被4
包裹独立出来了,在 2 内部的margin
会作用到父级,从而作用到父级相邻的 BFC 结构。我们继续在
4
上添加一个margin:10px 0
,神奇的事情发生了,居然还是一样边距被合并了,具体看下代码你会发现居然在
2
的外层加了magrin
,居然不会影响整个盒模型的高度。因此你再细品那句话
相邻块级格式上下文的上下边距会产生重叠
,于是你恍然大悟,143
是三个 BFC 结构,所以 4 设置margin
自然就被重合了。但是我要破坏这种相邻 BFC 结构,因此触发 BFC 结构的机会来了。我给
inner-box-2
加个样式,用overflow:hidden
触发生成一个新的 BFC;现在就变成了这样了 没错,盒子模型高度变成了
190
了,中间的4
外边距没有合并了。由于在
4
不是虽然不是根元素,但是身上加了overflow:hidden
触发4
形成一个新的 BFC,那么触发 BFC 还有其他什么方式吗?我们了解到除了
overflow:hidden
,还有以下几种方式overflow: auto;display: flex; display: table;display: -webkit-box; float: left;
已经确定的 BFC 不会与相邻浮动的 BFC 边距发生重合
当我们把
inner-box-2
设置为浮动后,边距就不会合并了。这也证实了相邻 BFC 与已经设置的浮动元素边距并不会合并,但inner-box-2
与inner-box-1
始终在一个大的BFC
包裹着,而每一个自身元素又形成一个独立的BFC
。 :::: code-group ::: code-group-item html::: ::: code-group-item css
::: ::::
探索 BFC 九宫格布局
我们知道相邻的 BFC 结构垂直方向外边距会合并,利用这点,我们实现九宫格布局 :::: code-group ::: code-group-item html
::: ::: code-group-item css
::: :::: 注意我们给所有的子元素加了浮动,那么此时会造成父元素高度坍塌,因此父级元素必须要加上
overflow:hidden
或者设置display: inlie-block
或者position: absolute
;这样才可以导致父级元素不坍塌。貌似
456
中间元素因为设置浮动破坏了BFC
,所以我们需要给456
设置特殊margin
才行,于是乎你给 456 加一层 div,然后设置margin: -10px 0
并且要设置左浮动
:::: code-group ::: code-group-item css::: ::: code-group-item html
::: :::: OK 已经可以了
此时我们这样改 dom 结构似乎有点不是很好,因为可能数据是从后端接口返回并不是写死的数据结构,因此我们再改下结构布局 :::: code-group ::: code-group-item html
::: ::: code-group-item css
::: :::: 我们最初把
margin
作用在每个小元素下,现在我们利用BFC
的特性,我们把margin
作用在item
上,因为三个item
就是相邻垂直方向的 BFC 结构,边距会产生合并,也正是利用边距合并巧妙的解决了保持边距相等的问题。具体可以看下效果 由于不同的布局方式,因此写出来的页面拓展性是完全不一样,拓展性强的布局方式,对于后期的维护是相当有益。因此不推荐第一种方式改结构,然后特殊设置
456
的父边距,虽然效果能达到一致,但是后期维护性与拓展性不高。BFC 实现自适应布局
有时候左侧固定,右侧自适应这种页面结构时常会有,这种布局方案有哪些可以实现呢 :::: code-group ::: code-group-item html
::: ::: code-group-item css
::: :::: 此时发现页面不尽人意,肯定是下面这样的 但是当我们给
slide-left
设置float:left
后,我们会发现,此时slide-left
的文档流被破坏,main
会紧贴着slide-left
排列此时我们可以观察到
main
贴着slide-left
,宽度就是父级的宽度但实际上
main
是需要剩下的宽度,他需要根据左侧的slide-left
的宽度而自适应 因此你可以,让main
成为一个独立 BFC,我们需要设置它oveflow:hidden
就行 那么此时就会变成 完整的 css 如下OK,现在就实现了右侧根据左侧宽度的大小自适应了。 更多关于 BFC 可以参考MDN BFC
总结
了解什么是 BFC,BFC 简称块级格式上下文,它是一块独立的区域影响子元素的排列,相邻区域的 BFC 边距会产生重合
触发 BFC 条件有,
display: flex
、display: inline-block
、display:box
,position:absolute
,或者oveflow: hidden/auto
,float:left
;利用 BFC 实现九宫布局,本质利用相邻 BFC 外边距合并
左侧固定,右侧自适应布局
本文 code example