说起 BFC, 就必须先了解一下 CSS 文档流中的定位机制, 而且这部分说简单也简单, 但却有个坑有可能误导我们, 特在本文作出解释.
一, 文档流中的定位机制
1. 三种基本方式
CSS 有三种基本定位机制, 我想大多数朋友都掌握了, 在此简要概述一下(不浪费时间):
普通流(或称常规流):CSS 默认的定位方式, 触发方式包括为 position: static/relative, 且 float:none
浮动: 浮动脱离普通流, 可以左右移动, 直到它的外边框边缘碰到包含框或另一个浮动框的边缘, 触发方式基本就是 float:left/top 等.
绝对定位: 盒子脱离普通流, 不影响普通流上其他元素的布局
2. 注意事项
所以, 此时大部分初学者都会结合现实世界感觉到这三种流的立体感就是如下图所示的这样:
这里我想说的是, 上图这种表达方式不能说是完全正确, 虽然层级明确了, 但这会给初学者带来错误的理解: 浮动元素既然已经玩飘了, 且普通流中的 div 也不会再给它留地方了, 那浮动元素对普通应该就彻底没影响了吧? 当然不是! 直接上个小例子看看(多余上色之类的代码去掉了):
- <body>
- <div class='parent'>
- <div class='child1'>
- Child1
- </div>
- <div class='child2'>
冷咖啡离开了杯垫
我忍住的情绪在很后面
- </div>
- </div>
- </body>
- <style>
- .parent {
- width:400px;
- min-height:100px;
- }
- .child1 {
- width:50px;
- height:50px;
- }
- .child2 {
- width:100px;
- height:100px;
- }
- </style>
效果如下:
好的, 那接下来, 按照我们的想法, 把 child1 设为浮动, 此时它就应该脱离普通流, 且普通流中的元素不再考虑它的位置了, child1 添加 float:left 后如下:
咦! child1 确实感觉浮动了, child2 也确实毫不客气的把 child1 原本的位置给顶替了, 可 child2 里面的元素是咋回事? 为什么像躲摔倒的老太太一样躲避 child1 了呢? 这就是我想提醒朋友们一定要注意的地方. 下面看看解释:
float 起初被设计出来的初衷其实是为了实现报纸上的那种文字环绕图片的效果, 就像我们上例这种普通流中的文字环绕在 child1 的周围. 但之后大家才发现结合 float + div 可以实现一定的网页布局, 所以, 这是浮动的特性. 即浮动只是脱离了文档流, 即不会按照你的设计而进行布局, 就算它在任何位置上那也是和文档流中的其他内容是是平级关系的, 我们在使用浮动时, 基本上就考虑它的布局定位就行了, 不要觉得它彻底飘了, 它的影响还在.
好了, 这个坑帮不知道的朋友解决了, 接下来就好理解 BFC 了.
二, BFC 探索之路
你可能在不知道 BFC 是啥玩意的前提下却知道解决子 div 浮动而造成父 div 塌陷的一个经典的办法就是给父 div 设置 overflow:hidden, 但要是面试官问你为啥, 你可能就歇菜了, 别问我怎么知道, 我曾经就是那个菜鸡..., 所以, 了解了 BFC, 你就知道为啥了.
1. BFC 概念
BFC(Block Formatting Context, 块格式上下文)是 web 页面的可视化 CSS 渲染的一部分, 并且有自身的一套渲染规则, 它决定了其子元素如何定位, 以及和其他元素的关系和相互作用.
2. BFC 特点
具有 BFC 特性的元素可以看成是隔离了的独立容器, 容器里面的元素不会在布局上影响到外面的元素, 并且 BFC 具有普通容器所没有的一些特性. 很多好的文章罗列的内容有:
内部的 box 会在垂直方向, 从顶部开始一个接一个地放置;
box 垂直方向的距离由 margin 决定, 属于同一个 BFC 的两个相邻的 box 的垂直方向的 margin 会发生叠加;
在 BFC 中, 每个盒子的左外边缘 (margin-left) 会触碰到容器的左边缘(border-left). 对于从右到左的格式来说, 则触碰到右边缘, 即使是浮动的也是如此, 即不会发生 margin 穿透;
形成了 BFC 的区域不会与 float box 重叠;
计算 BFC 高度时, 子浮动元素也参与计算(BFC 会确切包含浮动的子元素, 即闭合浮动);
所以, 再遇到下面这些问题时, 就可以回答了:
如何保证一个 div 元素不被同级的浮动元素覆盖: 设置该 div 元素为 BFC;
为什么父 div 设置 overflow:hidden 就可以在其子 div 为浮动的情况下依然可以撑开: 因为此时父 div 是个 BFC.
但是! 这里我还想说一下我的一些想法, 即: 我认为, 之所以提出 BFC 的概念, 其主要目的是为了隔离出独立容器, 而容器本身与其他元素之间是否完全满足上述特性, 这应该区别对待, 我们应该把 BFC 的核心思维用在它本身内部而非外部, 后面文章会有例子.
3. 触发 BFC 的条件
有朋友罗列了好多, 记住一些常规的即可:
根元素或包含根元素的元素, 这里应该就是 body 元素;
浮动元素(float 不是 none);
绝对定位元素(position:absolute/fixed);
行内块元素(display:inline-block);
表格单元格(display:table-cell ,html 表格单元格默认为该值);
表格标题(display:table-caption , HTML 表格标题默认为该值);
匿名表格单元格元素(display:table / table-row / table-row-group / table-header-group / table-footer-group / inline-table , 分别是 HTML table ,row,tbody,thead,tfoot 的默认属性);
overflow: 非 visible 的块元素;
- display:flow-root;
- contain:layout / content / strict;
弹性元素(display:flex / inline-flex 元素的直接子元素);
网格元素(display:grid / inline-grid 元素的直接子元素);
多列容器(元素的 column-count 或 column-width 不为 auto, 且包括 column-count 为 1);
column-span 为 all 的元素始终会创建一个新的 BFC, 即使该元素没有报过在一个多列容器中;
所以, 每次看到 overflow:hidden,float:left/right ,position:absolute/fixed , 不用怀疑, 一定是 BFC
4. 实际使用场景
BFC 在实际开发布局中基本可以做这两件事:
避免由于子元素浮动造成父元素塌陷;
避免同一个 BFC 中的两个块级元素的垂直方向 margin 重叠(设置其中一个为一个新的 BFC, 永久隔绝外部影响);
自适应两栏布局.
5. BFC 实例
直接看看吧
- <body>
- <div class='box'>
- <div class='left'>左边</div>
- <div class='right'>右边
- <div class='little'>1</div>
- <div class='little'>2</div>
- <div class='little'>3</div>
- </div>
- </div>
- </body>
- <style>
- .box {
- background:#888;
- overflow:hidden;
- margin-left:50px;
- }
- .left {
- background: #73DE80; /* 绿色 */
- width:200px;
- height:200px;
- }
- .right {
- background: #EF5BE2; /* 粉色 */
- width:400px;
- min-height:100px;
- }
- .little {
- background: #fff;
- width: 50px;
- height: 50px;
- margin: 10px;
- float:left;
- }
- </style>
效果如下:
如果突然把 div left 元素 添加一个 float:left:
看到了吧! div right 元素的子元素腾地方了, 那接下来把 div right 变成一个 BFC, 比如使用: overflow:hidden, 效果如下:
这样, 就满足了 BFC 内部元素不受外界干扰, 且不会与 float 元素重叠两个特性.
但是, 如果我给 box right 元素设置了绝对定位, 那它是会覆盖 box left 这个浮动元素的, 可这就不符合 BFC 的不会与 float 元素重叠这个特性了:
所以我提出了我和我同事讨论出的想法, 即我们不能把上述罗列的 BFC 特性彻底肯定, 因为这里涉及到的是两个大的知识层. 当设置了绝对定位, 虽然也触发了 BFC, 但是它更是直接影响了层级关系, 所以优先实现后者.
以上就是我想提醒广大和我一样的初级朋友, 欢迎大家批评指正, 谢谢您!!!~~~
参考文献
《学习 BFC》 juejin.im/post/59b73d...
《关于 BFC 理解》 http://reng99.cc/2018/08/12/about-BFC/
来源: https://juejin.im/post/5c540b0bf265da2d896302ef