走在前端的大道上
本篇将自己读过的相关 盒模型 BFC 文章中,对自己有启发的章节片段总结在这(会对原文进行删改), 会不断丰富提炼总结更新。
一. 常见定位方案
在讲 BFC 之前,我们先来了解一下常见的定位方案,定位方案是控制元素的布局,有三种常见方案:
普通流 (normal flow) 在普通流中,元素按照其在 HTML 中的先后位置至上而下布局,在这个过程中,行内元素水平排列,直到当行被占满然后换行,块级元素则会被渲染为完整的一个新行,除非另外指定,否则所有元素默认都是普通流定位,也可以说,普通流中元素的位置由该元素在 HTML 文档中的位置决定。
浮动 (float) 在浮动布局中,元素首先按照普通流的位置出现,然后根据浮动的方向尽可能的向左边或右边偏移,其效果与印刷排版中的文本环绕相似。
绝对定位 (absolute positioning) 在绝对定位布局中,元素会整体脱离普通流,因此绝对定位元素不会对其兄弟元素造成影响,而元素具体的位置由绝对定位的坐标决定。
二、BFC 概念
Formatting context(格式化上下文) 是 W3C CSS2.1 规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。常见的 FC 有 BFC、IFC,还有 GFC 和 FFC。
那么 BFC 是什么呢?
BFC 即 Block Formatting Contexts (块级格式化上下文),它属于上述定位方案的普通流。
一个 BFC 的范围 包含创建该上下文元素的所有子元素,但不包括创建了新 BFC 的子元素的内部元素。这从另一方角度说明,一个元素不能同时存在于两个 BFC 中。因为如果一个元素能够同时处于两个 BFC 中,那么就意味着这个元素能与两个 BFC 中的元素发生作用,就违反了 BFC 的隔离作用。
具有 BFC 特性的元素可以看作是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素,并且 BFC 具有普通容器所没有的一些特性。
通俗一点来讲,可以把 BFC 理解为一个封闭的大箱子,箱子内部的元素无论如何翻江倒海,都不会影响到外部。
三、布局规则
内部的 Box 会在垂直方向上一个接一个的放置
每个元素的左外边距与包含块的左边界相接触(从左向右),即使浮动元素也是如此。(这说明 BFC 中子元素不会超出他的包含块,而 position 为 absolute 的元素可以超出他的包含块边界)
属于同一个 BFC 的 两个相邻 Box 的 上下 margin 会发生折叠;
BFC 的区域不会与 float 的元素区域重叠(阻止元素被浮动元素覆盖)
计算 BFC 的高度时,浮动子元素也参与计算(清除内部浮动)
四、触发 BFC
只要元素满足下面任一条件即可触发 BFC 特性:
body 根元素
浮动元素:float 除 none 以外的值,如 left、right
绝对定位元素:position (absolute、fixed)
display 为 inline-block、table-cells、flex
overflow 除了 visible 以外的值,如 hidden、auto、scroll
注意:有些文章中说 HTML 可以触发 BFC,没有说 body,按照上边介绍的一个 BFC 的范围和下边的案例 1 来看,HTML 能不能触发不确定,但是 body 是可以的
五、BFC 的特性及应用
1. 普通流中两个相邻的块元素 垂直方向上的 margin 会折叠
<style>
.p {
width:200px;
height:50px;
margin:50px 0;
background-color:red;
}
</style>
<body>
<div class=”p”></div>
<div class=”p”></div>
</body>
效果图是:
发生外边距折叠,是因为他们 同属于 body 这个根元素让 它们 不属于同一个 BFC,就能避免外边距折叠:
<style>
.wrap {
overflow:hidden;
}
.p {
width:200px;
height:50px;
margin:50px 0;
background-color:red;
}
</style>
<body>
<div class=”p”></div>
<div class=”wrap”>
<div class=”p”></div>
</div>
</body>
效果图是:
2. 普通流中 父子嵌套关系的 2 个块元素 垂直方向上的 margin 会折叠
<style>
.father {
width: 200px;
height: 200px;
background: skyblue;
}
.son {
width: 100px;
height: 100px;
background: red;
}
</style>
<body>
<div class=”father”>
<div class=”son”></div>
</div>
</body>
然后, 我们给子元素添加一个 margin-top: 50px 时
.son {
width: 100px;
height: 100px;
background: red;
margin-top: 50px;
}
我们神奇的发现父子元素同时 ” 掉下来了 50px”, 如图所示
3.BFC 可以包含浮动的元素(清除浮动)
正常情况下,浮动的元素会脱离普通文档流,所以下面的代码里:
<style>
.wrap {
border: 1px solid #000;
}
.inner {
float: left;
width: 50px;
height: 50px;
background: #eee;
}
</style>
<body>
<div class=”wrap”>
<div class=”inner”></div>
</div>
</body>
外层的 div 会无法包含 内部浮动的 div,效果见下图:
但如果我们 触发外部容器的 BFC,根据 BFC 规范 计算 BFC 的高度时,浮动元素也参与计算,那么外部 div 容器就可以包裹着浮动元素,所以只要把代码修改如下:
<style>
.wrap {
border: 1px solid #000;
overflow:hidden;
}
.inner {
float: left;
width: 50px;
height: 50px;
background: #eee;
}
</style>
<body>
<div class=”wrap”>
<div class=”inner”></div>
</div>
</body>
就可以完成以下效果:
4. 实现 2 栏自适应布局
要求左侧固定 300px, 右侧自适应的布局
<style>
.wrapper, * {
padding: 0;
margin: 0;
}
.left {
width: 300px;
height: 100px;
background: red;
float: left;
}
.right {
height: 100px;
background: skyblue;
overflow: hidden;
}
</style>
<div class=”wrapper”>
<div class=”left”>left</div>
<div class=”right”>right</div>
</div>
原理:BFC 元素不会和浮动的元素重叠
参考文章:10 分钟理解 BFC 原理 CSS 中重要的 BFC 浅析 CSS 里的 BFC 和 IFC 前端人人都应该理解的盒模型 BFC 渲染机制