盒模型是一个渲染标准,而盒子是渲染出来的实际区域。
盒子只分块级盒子和行内盒子两种,任何一个盒子总是块级盒子或行内盒子中的一种。取决于 CSS display 属性的第一个属性值。格式上下文是一个以特定布局规则布局子元素的独立区域,BFC 就是按照块级布局规则布局子元素的格式上下文(独立区域)。
盒子总是在其对应的格式上下文中工作,因此任何一个盒子总是某个格式上下文中的一部分。\
块级盒子是在块格式上下文(BFC)中工作的盒子,行内盒子是在行内格式上下文(IFC)中工作的盒子。
一、盒模型、盒子、块级盒子
1、相关概念
-
盒模型(box model)
是浏览器进行布局渲染时依据的渲染标准。 -
盒子(box)
浏览器渲染后呈现出来的一个个矩形的区域。 -
包含块(containing block)
一般(不浮动)是这个元素最近的祖先块元素的内容区域;即离它最近的上一个块级元素。 -
块级元素(block-level element)
布局是块布局的元素。元素是否是块级元素仅是元素本身的属性,并不直接用于格式化上下文的创建或布局。 -
块级盒子(block-level box)
由块级元素生成的盒子。一个块级元素至少会生成一个块级盒子,但也有可能生成多个(例如列表项元素)。 -
块容器盒子(block container box)
块容器盒子侧重于当前盒子作为“容器”的这一角色,它不参与当前块的布局和定位,它所描述的仅仅是当前盒子与其后代之间的关系。换句话说,块容器盒子主要用于确定其子元素的定位、布局等。
也就是说,能够影响其后代盒子布局的块级盒子就是一个块容器盒子。 -
块盒子(block box)
如果一个块级盒子同时也是一个块容器盒子,则称其为块盒子。除具名块盒子之外,还有一类块盒子是匿名的,称为匿名块盒子(Anonymous block box),匿名盒子无法被 CSS 选择符选中。
二、盒子
每个盒子由四部分区域组成,由内而外依次是:
- 内容区域 Content Area
- 内边距区域 Padding Area
- 边框区域 Border Area
- 外边框区域 Margin Area。
盒模型会根据盒子的包含块的边界来渲染盒子。盒子创建后,自身就成为一个包含其后代元素的包含块。
1、盒子类型
盒子有不同的类型,不同类型的盒子的格式化方法也有所不同。盒子的类型取决于 CSS display 属性。
-
块级盒子是在块格式上下文(Block Formatting Context)中工作的盒子。
在BFC中,盒子会从包含块的顶部开始,按序垂直排列。
相邻两个块级盒子之间的垂直间距会遵循外边距折叠原则被折叠。 -
inline box(行内盒子)
行内盒子是在行内格式上下文(Inline Formatting Context)中工作的盒子。
在IFC中,盒子会从包含块的顶部开始,按序水平排列。
只有水平外边距、边框和水平内边距会被保留;其他属性会无效。
这些盒子可以以不同的方式在垂直方向上对齐:可以底部对齐或顶部对齐,或者按文字底部进行对齐。
每一行文字的高度则由 line-height 属性决定。
2、盒子布局
是一种基于盒子与其兄弟和祖辈盒子的交互方式来确定盒子的位置和大小的算法。有以下几种形式:
- 块布局:用来布置文件。块布局包含以文档为中心的功能,例如 浮动元素或将其放置在多列上的功能。
- 行内布局:用来布置文本。
- 定位布局:用来对那些与其他元素无交互的定位元素进行布置。
- 表格布局:用来布置表格。
- 弹性布局:用来布置那些可以顺利调整大小的复杂页面。
- 网格布局:用来布置那些与一个固定网格相关的元素。
3、定位规则
定位盒子时所使用的规则:
- 普通流:按照次序依次定位每个盒子。
- 浮动:将盒子从普通流中单独拎出来,将其放到外层盒子的某一边。
- 绝对定位:按照绝对位置来定位盒子,其位置根据盒子的包含元素所建立的绝对坐标系来计算,因此绝对定位元素有可能会覆盖其他元素
4、块级盒子的外边距折叠
块级元素之间的垂直外边距会发生合并折叠为单个边距,其大小为两个边距中的最大值(或如果它们相等,则仅为其中一个),这种行为称为外边距折叠。
注意:有设定浮动和绝对定位的元素不会发生外边距折叠。
有三种情况会形成外边距折叠:
- 相邻的兄弟元素。
- 没有内容将父元素和后代元素分开。
- 空的区块。
折叠原则:
- 如果包含负边距,折叠后的外边距的值为最大的正边距与最小(绝对值最大)的负边距的和。
- 如果所有的外边距都为负值,折叠后的外边距的值为最小(绝对值最大)的负边距的值。这一规则适用于相邻元素和嵌套元素。
- 外边距折叠仅与垂直方向有关。
- display 设置为 flex 或 grid 的容器中不会发生外边距折叠。
5、匿名块盒子
具体说明见代码,其 <p> 标签前后的文本就是匿名块盒子。
<div class="flex">
I am wrapped in an anonymous box
<p>I am in the paragraph</p>
I am wrapped in an anonymous box.
</div>
<style>
.flex {
display: flex;
}
.flex > * {
background-color: rebeccapurple;
color: white;
}
</style>
CSS 选择器不能作用于匿名盒子 (anonymous boxes),所以它不能被样式表赋予样式。也就是说,此时所有可继承的 CSS 属性值都为 inherit ,而所有不可继承的 CSS 属性值都为 initial。
三、格式化上下文(Formatting Context)
格式化上下文(Formatting Context)是一个以特定布局规则(块、行内、弹性)显示的独立区域;而外部元素使用的布局规则称为对应的格式上下文,其中的内部元素则都是按照格式上下文对应的特定布局规则进行布局。
BFC是一个独立的渲染区域,它的内容(子元素)不会被外部元素影响;也就是说它是一块具有独立作用域的内容块。
格式化上下文影响布局;如清除浮动,消除父子之间的外边距折叠等。
格式化上下文包括几种规则类型:
-
区块格式化上下文 (Block Formatting Context,简称 BFC)
其内部元素使用块布局规则进行布局。 -
行内格式化上下文 (Inline Formatting Context,简称 IFC)
其内部元素使用行内布局规则进行布局。 -
弹性格式化上下文 (Flex Formatting Context)
其内部元素使用块弹性规则进行布局。 -
网格格式化上下文 (Grid Formatting Context)
其内部元素使用块网格规则进行布局。 -
表格格式化上下文 (Table Formatting Context)
其内部元素使用块表格规则进行布局。
四、块级盒子与BFC
块级盒子是在块格式上下文(BFC)中工作的盒子。
文档的根元素 (<html>) 是一个特殊的BFC,叫做初始块格式上下文(),页面上的所有内容都是BFC的一部分。这意味着 <html> 元素块中的每个元素都是按照正常流(Normal Flow)遵循块和行内布局规则进行布局的。
除了原生的 BFC <html> 外,可以根据需要自己创建一个新的 BFC用于实现某些布局。
1、创建一个新的 BFC:
- 文档的根元素(<html>)。
- 浮动元素(即 float 值不为 none 的元素)。
- 绝对定位元素(position 值为 absolute、sticky 或 fixed 的元素)。
- 元素属性为 display: flow-root 或 display: flow-root list-item
- 弹性元素(display 值为 flex 或 inline-flex 元素的直接子元素),如果它们本身既不是弹性、网格也不是表格容器。
- 网格元素(display 值为 grid 或 inline-grid 元素的直接子元素),如果它们本身既不是弹性、网格也不是表格容器。
- 行内块元素(display 值 table 和为 inline-block 的元素)。
- 表格单元格(display 值 table 和使用 display: table-* 属性的所有表格单元格)。
- 表格标题(display 值为 table-caption,HTML 表格标题默认值)。
- overflow 值不为 visible 或 clip 的块级元素。
- contain 值为 layout、content、strict 或 paint 的元素。
- 元素属性 column-span 设置为 all
- 多列容器(column-count 或 column-width 值不为 auto,且含有 column-count: 1 的元素)。 column-span 值为 all 的元素始终会创建一个新的格式化上下文,即使该元素没有包裹在一个多列容器中(规范变更、Chrome bug)
2、使用 新BFC 的作用影响
它将:
- 包含内部浮动。
- 排除外部浮动。
- 阻止外边距重叠。
具体示例见:MDN CSS display BFC
以下为消除父子外边距折叠的示例:
<div class="parent">
<div class="child">子元素</div>
</div>
<style>
.parent {
outline: 2px solid cornflowerblue;
background-color: gainsboro;
width: 200px;
}
.child {
outline: 2px solid darkorange;
background-color: oldlace;
width: 100px;
height: 50px;
}
.parent, .child {
margin: 20px;
}
// 添加下面的样式后,即可消除父子外边距折叠
.parent {
display: flow-root;
}
</style>
有父子外边距折叠时(橙色为外边距区域):
消除父子外边距折叠后(橙色为外边距区域):