BFC(
Block Formatting Context
)俗称块级格式上下文,初次看到这词似乎有点不是很理解,通俗解释就是一个独立区域决定了内部元素的排放,以及内部元素与外部元素的相互作用关系
正文开始...
BFC是什么
俗称块级格式上下文,一块独立的区域决定了内部元素的位置排列,以及内部元素与外部元素的作用关系
BFC特点
我们先了解下BFC
有什么特点
1、垂直方向,相邻BFC
的块级元素会产生外边距合并
2、BFC包含浮动元素,浮动会触发新的BFC产生
3、已经确定的BFC区域不会与相邻BFC的浮动元素边距发生重合
针对以上几点我们来具体深究一下BFC的特性到底有何区别,在什么样的场景下会比较触发BFC
新建一个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
这个元素决定了内部的元素排放,因为子元素始终是被包裹起来的,因为是块级元素,所以单行排列。
接下来我们将子元素添加外边距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
是三个块级元素,在wrap-box
内部来说,这三个内部div
形成独立的BFC
,所以相邻的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结构。
我们继续在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
,居然不会影响整个盒模型的高度。
因此你再细品那句话相邻块级格式上下文的上下边距会产生重叠
,于是你恍然大悟,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;
.inner-box-2 { margin: 10px 0; 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
。
<div class="wrap-box"> <div class="inner-box inner-box-1">1</div> <div class="inner-box inner-box-2">2</div> </div>
<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九宫格布局
我们知道相邻的BFC结构垂直方向外边距会合并,利用这点,我们实现九宫格布局
<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>
对应的css
如下
*{ 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
;这样才可以导致父级元素不坍塌。
貌似456
中间元素因为设置浮动破坏了BFC
,所以我们需要给456
设置特殊margin
才行,于是乎你给456加一层div,然后设置margin: -10px 0
并且要设置左浮动
.item-2 { float: left; margin: -10px 0; }
<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结构似乎有点不是很好,因为可能数据是从后端接口返回并不是写死的数据结构,因此我们再改下结构布局
<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结构,边距会产生合并,也正是利用边距合并巧妙的解决了保持边距相等的问题。
具体可以看下效果
由于不同的布局方式,因此写出来的页面拓展性是完全不一样,拓展性强的布局方式,对于后期的维护是相当有益。因此不推荐第一种方式改结构,然后特殊设置456
的父边距,虽然效果能达到一致,但是后期维护性与拓展性不高。
BFC实现自适应布局
有时候左侧固定,右侧自适应这种页面结构时常会有,这种布局方案有哪些可以实现呢
<h1>左边固定,右边自适应,右边随着左边的宽度而自适应</h1> <div class="wrap-box"> <div class="slide-left">left</div> <div class="main">main</div> </div>
对应的css
*{ 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 { width: 100px; height: 100px; background-color: red; resize:horizontal; float: left }
此时我们可以观察到main
贴着slide-left
,宽度就是父级的宽度
但实际上main
是需要剩下的宽度,他需要根据左侧的slide-left
的宽度而自适应 因此你可以,让main
成为一个独立BFC,我们需要设置它oveflow:hidden
就行 那么此时就会变成
完整的css如下
*{ 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,BFC简称块级格式上下文,它是一块独立的区域影响子元素的排列,相邻区域的BFC边距会产生重合
- 触发BFC条件有,
display: flex
、display: inline-block
、display:box
,position:absolute
,或者oveflow: hidden/auto
,float:left
;
- 利用BFC实现九宫布局,本质利用相邻BFC外边距合并
- 左侧固定,右侧自适应布局
- 本文 code example[2]