真是一个小例子引发的“命案”呀,原本只是在想为什么一个容器内的块元素几个块元素会发生外边距(margin collapse),然后找啊找啊找,就找到了BFC(Block Formating context)。>
真是很福气自己,被自己感动哭了
首先,我会从 BFC是什么? 如何形成BFC? BFC的应用 这三个方面入手。
1 BFC 是什么?
BFC 是web页面中盒模型布局中的CSS渲染模式,定位机制属于普通流模式。
一个块格式化上下文(block formatting context) 是Web页面的可视化CSS渲染出的一部分。它是块级盒布局出现的区域,也是浮动层元素进行交互的区域。
(我们都知道,CSS中的定位机制有三种形式:1 普通流模式 2 浮动 3 定位。)BFC其实就是一个独立的布局环境,其中的元素不受外界影响。> 我知道你现在看到这里肯定还不知道我在说什么,说实话,我一开始看其他文章也是这样的,还是继续往下看,回头再来理解概念吧。
2 创建BFC
一个元素要创建BFC,需要满足以下几个条件,才能形成BFC。
- float的值不是none.
- position 的值不是static或者relative。
- display的值是inline-block,table-cell,flex,table-caption或者inline-flex。(其实这个除了flex其他我好像都没用过)
- overflow的值不是visible。
所以,只要满足以上四个条件就可以创建BFC了,但是,等等,我们要创建BFC干嘛?首先应该知道BFC的实际用处,我们才会在实际应用中使用它。那么接下来就是,BFC的作用,我会用好多个例子来证明一下。
3 BFC的特性 (人家虽然好用,也是有缺点的,例如外边距合并问题)
- 1 BFC内的元素会导致 外边距合并。 (在BFC当中,盒子都是从它的包含块一个一个垂直放置的,两个相邻盒子的垂直间距取决于margin属性,所以两个相邻块会发生垂直外边距塌陷。)
- 2 BFC中每一个盒子的左外侧紧贴包含块的左侧,(从右到左的格式里,则为盒子右侧紧贴包含快右侧)甚至有浮动也是如此。(浮动的元素是脱离文档流的,所以其他元素为将其当作不存在)。
- 3 计算BFC的高度时,浮动元素也会计算进内。(所以,你懂的,我们可以给包含有浮动元素的父元素,设置成BFC,就可以 解决浮动元素导致的父元素坍塌的问题。)
- 4 BFC元素不会与浮动元素重合。 !!!理解这个很重要!!!!
BFC元素不会与浮动元素重合。 我需要说明一点就是,这是一个清除浮动的很好的方式啊啊啊。
1 当一个容器中有一个左浮动元素和一个BFC元素的时候,BFC的宽度如果可以在剩余空间存放的话,就会显示在浮动元素所在行的剩余空间内。
2 当 BFC 的宽度大于容器剩余宽度时,最新版本的浏览中只有firefox会在同一行显示,其它浏览器均换行。
是不是有点晕了,这个时候最好不要放弃,继续往下看,重头戏还在后头,知道了这些基础的东西之后,我们需要知道一些关于BFC的实践应用和基本原理。
4 BFC 实践及其原理。
1 自适应两栏布局 (原理参照:BFC的第4条属性。)
先看下面的代码:
CSS部分:
<style>
.container {
width:400px;
margin:200px;
}
.leftpart {
float: left;
width:100px;
height:200px;
background: plum;
color: white;
}
.rightpart {
height:300px;
background: pink;
color: white;
}
</style>
html部分:
<body>
<div class="container">
<div class="leftpart">我是左边的那一块</div>
<div class="rightpart">我是右边的那一块,听说我会环绕在左边的浮动元素上,我也是没办法啊,因为浮动元素是脱离文档流的,我谁将它当作不存在,然后占据他所在的空间呢
也只有将我设置成BFC的形式,我才不会这样呢?不信你试一试</div>
</div>
</body>
左边的设置了左浮动,因为浮动元素脱离文档流,所以结果会是下面这个样子。
image.png很显然,这不是我们想要的结果,前面提到了BFC的特性中,有一条提到,BFC不会与浮动元素触碰,那么我们是不是可以给右边的元素设置成BFC。
那么其实,就是在.rightpart
设置多一个样式属性就可以了。
.rightpart {overflow:auto;} // 前面提到了如何形成一个BFC,可以设置overflow不为visible。
那么,我们来看看效果图。
image.png这样,我们右边的那一块,没有设置宽度,会自动根据容易的宽度还有浮动元素的宽度,自适应的分配宽度给右边那一块。这样也给我们的自适应布局提供了思路呀。
对了,如果希望左右两栏有间距,你可以这么做。
你会发现,你给右边那一块设置了margin-left
之后,并没有你理想中那样。假设我添加了
.rightpart {margin-left:20px;} // 只是设置了20
你会发现。这两栏看上去还是没有间距的。其实从下图可以发现,不是margin不起作用。
image.png我的理解是,margin-left
确实是起作用了,但是它其实还是将浮动元素看做是不占据文档流的,只是BFC元素的盒模型中border内的不再去抢浮动元素的空间,但是margin
还是会抢占浮动元素的空间的。所以,要想看到两栏有间距,需要设置的margin-left
要大于leftpart
的宽度。
(当然,这并不是明智之举,要是你不知道leftpart的宽度,岂不是悲剧了)
试一下:
.rightpart {margin-left:120px;} // 只是设置了120
image.png
其实,不用那么麻烦。我们只需要给 leftpart
设置margin-right 就可以了。
上面其实也只是想详细的去理解这个过程。
.leftpart {margin-right:20px;}
image.png
不知道你有没有发现,如果我们之前不设置BFC的话,也就是不给rightpart
设置成BFC的话,直接就是设置rightpart的margin-left大于左浮动元素的宽度,也可以达到两栏布局的效果,但是,~~~那样很麻烦啊,如果不知道宽度怎么办。
所以,两栏布局的最佳实践应该是: margin-left + BFC模式。
(当然,用flex布局会更加方便,但是这也不失为一种好方法呀。)
2 解决含有浮动元素的父元素塌陷问题
首先,这个问题的存在原因是因为浮动元素是脱离文档流的,所以包裹浮动元素的父元素其实并不能被撑开,所以就会导致下面的结果,看一下图。
image.png上例所示图的代码如下:
// 很明显,两个子模块的定位都是浮动形式,而父元素发生了坍塌。
html部分:
<body>
<div class="mainPart">
<div class="testpart"></div>
<div class="testpart"></div>
</div>
</body>
CSS部分:
.mainPart {
background: royalblue;
border:1px solid olivedrab;
width:500px;
}
.testpart {
float: left;
width:200px;
height:200px;
background: plum;
margin:10px;
}
那么?怎么解决这个问题。
当然。你可以向通常的清除浮动的方法一样,在父元素内部添加一个空元素,设置clear:both;
可以达到清除浮动的效果。
那如何通过设置一个BFC去清除浮动呢?
前面第3点中提到:
计算BFC的高度时,浮动元素也会计算进内。
所以,可以将父元素设置成BFC,就可以达到清除浮动,清除高度坍塌问题。
// 给父元素添加以下样式
.mainPart {
overflow:auto;
}
那么,效果如下图:
image.png所以,可以通过给父元素设置成BFC来清除浮动。
3 BFC内部元素外边距塌陷问题解决。
前面提到的BFC的原理特性中,有一个就是外边距合并问题。(这又是一个大boss,我最近也在看这方面的资料,后续会补上详细的笔记的)
BFC垂直方向上的距离由margin值所决定,同一个BFC内的两个相邻元素的margin值会重叠。
什么意思捏~~~~
先看下图:
其实两个粉色的子元素,已经设置了margin值为20了。按照道理来说的话,上下两块之间的距离应该是40的。但是这里只是20.也就是外边距合并最后是取比较大的那一个。
(其实我想了一下,我觉得这个外边距合并用在这里挺好的呀,有时候如果我们想实现下面这样一个效果,其实我觉得外边距合并的存在反倒是好的呢)
只需要给每一个子元素设置margin为20即可。(当然,父元素和第一个子元素以及最后一个子元素也会发生合并问题, ~~啊啊啊,我后面会贴上一文章来解释的,~~)
针对这种子元素发生外边距合并的处理方法。
我们可以将子元素重新设置成一个BFC就可以了。
你想想,一开始,在同一个BFC下的子元素之所以会发生垂直外边距合并(对了,外边距合并只发生在垂直方向,水平方向不会的。),是因为父元素的高度是由子元素决定的,所以高度也会发生外边距合并了。
解决方法就是,用一个元素给第二个子元素包在一个新的BFC内。
html部分:
<div class="father">
<div class="son"></div>
<div style="overflow: auto"> // 这里设置了父元素,同时设置overflow:auto。
<div class="son" ></div>
</div>
</div>
CSS部分:
.father {
width:100px;
height:200px;
background: red;
/*margin:20px;*/
}
.son {
width:30px;
height:90px;
margin: 20px;
background: plum;
}
这样的话,结果就如下所示了:
image.png后记: 我理解的BFC其实就是CSS中的一个渲染机制,BFC就相当于一个盒子,内部的元素与外界的元素互不干扰。它不会影响外部的布局,外部的布局也不会影响到它。你想一下,为什么设置了BFC之后就可以清除浮动,我的理解就是,设置了BFC之后的元素就是一个独立的个体,内部有浮动元素也不会再影响外部的元素了。那为什么设置了BFC之后,不会发生对周围元素的环绕现象,也是同一个道理。所以,这么去想一想,其实BFC我们就一直有在使用,只是自己不知道而已。
网友评论