页面渲染规则之BFC
前言
我们的css中有许多页面渲染规则,它是浏览器用来解释和显示网页样式的一系列原则,决定了元素如何在页面上呈现。比如说:选择器优先级,层叠机制,继承,盒模型,流布局,视觉格式化模型,媒体查询,css动画和转换,性能优化等等,今天我们重点讲讲属于视觉格式化模型中的BFC,是面试中高频的考查部分。
盒模型
我们先来唠唠盒模型。在css中我们有两种盒模型,分别是:标准盒模型和IE盒模型,我们在实际开发中可以选择适合的盒模型进行使用,在现代浏览器中,默认使用的盒模型是标准盒模型。我们来看看它们两者的区别:
<style>
*{
margin: 0;
padding: 0;
}
/* 盒模型 + 块级 */
.box,.box2,.box3{
width: 100px;
height: 100px;
padding: 10px;
border: 1px solid red;;
background-color: green;
}
.box2{
/* border 以内盒子的大小(包括border)IE 怪异盒模型*/
box-sizing: border-box;
}
.box3{
/* 默认值,标准盒模型 wh 设置的就是 content 的大小*/
box-sizing: content-box;
}
</style>
</head>
<body>
<div class="box"></div>
<div class="box2"></div>
<div class="box3"></div>
</body>
在这里我们加入了三个盒子,其中box1
和box3
是标准盒模型,box2
是IE盒模型,我们给它们都设置了width:100px;height:100px;
来看看它们在页面中的效果:
为什么大小会不一样呢,打开浏览器的开发者工具检查一下,点击我们的box1
和box3
,可以看到:
我们设置的宽高只是内容的宽高,也就是content
,并不包括padding,border
,那box2
呢:
我们可以发现它的content + padding +border
加起来才是我们设置的100px。
接下来我们来看另一个例子:
<style>
*{
margin: 0;
padding: 0;
}
div{
width: 100px;
height: 100px;
border: 1px solid red;
padding: 10px 20px;
}
span{
width: 100px;
height: 100px;
background-color: green;
}
</style>
</head>
<body>
<div>123</div>
<span>11</span><span>222</span>
</body>
页面呈现的是这个效果,诶为什么我们给span
设置了宽高它还只是这么一点呢,这是因为行内元素不能被设置宽高,它们是根据文本流来排列的,只会占据必要的空间。 如果想要改变,我们可以改变它的display
,行内元素默认值为inline
,我们将它设置为display:block
。
就作为块级元素显示了,并且可以设置宽高,同样我们可以将div
也作为行内元素显示:display:inline
。
还有display:nline-block
它可以让元素像行内元素一样显示,并且可以设置高度:
BFC
BFC(Block Formatting Context,块级格式化上下文),是web页面中盒模型布局的一种CSS渲染模式,它是一个独立的渲染区域,在内部的html元素按照一定的规矩进行布局,内部的元素不会受到外部元素的影响。接下来我们慢慢学习它的特性:
- 垂直排列:内部的Box(块级元素)会在垂直方向上一个接一个地放置,即每个块级元素独占一行。
- 外边距折叠:属于同一个BFC的两个相邻Box的margin会发生叠加,这种现象称为“margin塌陷”。
style>
* {
margin: 0;
padding: 0;
}
.box {
width: 200px;
height: 200px;
background-color: lightblue;
border: 1px solid black;
}
.box1{
margin-bottom: 50px;
}
.box2{
margin-top: 30px;
}
</style>
</head>
<body>
<div class="box box1">Box1</div>
<div class="box box2">Box2</div>
</body>
可以看到我们为box1
设置了margin:50px
,为box2
设置了margin:30px
,按道理来说它们的间距应该是80px
,但是并没有,就如同规则所说一样,margin
会进行重叠,最终的间距值取决于margin
大的那一方。我们可以通过为box2
增添一个父容器并设置其属性为overflow:hidden
来创建一个新的BFC
。这样就可以解决高度塌陷的问题。
<div style="overflow: auto;">
<div class="box box2">Box2</div>
</div>
- 不与浮动元素重叠:BFC的区域不会与float box重叠。这意味着如果一个元素形成了一个新的BFC,那么它将不会被浮动元素覆盖。
<style>
.container {
border: 2px solid black;
padding: 10px;
}
.float-box {
float: left;
width: 150px;
height: 100px;
background-color: lightblue;
margin: 10px;
}
.bfc-box {
width: 300px;
height: 100px;
background-color: lightgreen;
/* overflow: auto; 创建 BFC */
}
</style>
</head>
<body>
<div class="container">
<div class="float-box">这是一个左浮动的盒子</div>
<div class="bfc-box">这是一个创建了 BFC 的盒子</div>
</div>
</body>
当我们为container
增加一个overflow:auto
创建BFC后:
- 包含浮动:计算BFC的高度时,浮动元素也参与计算。这可以用来解决父元素因为浮动子元素而高度坍塌的问题。
<style>
/* 而用 BFC 清除浮动的原理就是:计算 BFC 的高度时,浮动元素也参与计算。只要触发父元素的 BFC 即可。 */
.parent {
background-color: red;
/* overflow: hidden; */
}
.child {
float: left;
height: 200px;
width: 200px;
background-color: green;
}
</style>
</head>
<body>
<div class="parent">
<div class="child"></div>
</div>
</body>
可以看到此时,parent
元素高度为0,当我们为他加上overflow:hidden
创建一个BFC后:
5. 隔离性:BFC就是页面上的一个独立容器,容器里面的子元素不会影响外面的元素,也不会受到外部元素的影响。
<style>
.container {
border: 2px solid black;
padding: 10px;
}
.float-box {
float: left;
width: 150px;
height: 100px;
background-color: lightblue;
margin: 10px;
}
.bfc-box {
width: 300px;
height: auto;
background-color: lightgreen;
/* overflow: auto; 创建 BFC 切换 */
padding: 10px;
border: 1px solid #ccc;
}
</style>
</head>
<body>
<div class="container">
<div class="float-box">这是一个左浮动的盒子</div>
<div class="bfc-box">
<p>这是创建了 BFC 的盒子内部的内容。</p>
<p>注意,这个内容不会被外部的浮动元素影响。</p>
</div>
</div>
在我们未创建BFC时,bfc-box
中的元素受到浮动元素的影响导致文字环绕着浮动元素,但是为它创建一个BFC后:
7. 左对齐:每个元素的margin box的左边,与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
<style>
*{
margin: 0;
padding: 0;
}
.container{
border: 2px solid black;
padding: 10px;
/* 父元素的不影响子元素的布局 */
/* overflow: hidden; */
}
.float-left{
/* 启动了一个新的FFC */
float: left;
width: 150px;
height: 100px;
background-color: lightblue;
margin: 10px;
}
.margin-box{
width: 200px;
height: 100px;
background-color: lightgreen;
margin: 20px 0 20px 50px;
}
</style>
</head>
<body>
<div class="container">
<div class="float-left">这是一个左浮动的元素</div>
<div class="margin-box">这是有左侧外边距的盒子这是有左侧外边距的盒子这是有左侧外边距的盒子</div>
</div>
形成BFC的条件
1. 根元素(HTML)
-
条件:HTML 文档的根元素(
<html>
)总是会形成一个新的 BFC。 - 解释:根元素是页面的最外层容器,它自然会创建一个独立的渲染区域。
2. 浮动元素(float
不为 none
)
-
条件:当一个元素的
float
属性设置为left
或right
时,它会形成一个新的 BFC。 - 解释:浮动元素从普通流中部分脱离出来,为了确保浮动元素不会影响其他非浮动元素的布局,浏览器会为浮动元素创建一个新的 BFC。
3. 绝对定位或固定定位元素(position
为 absolute
或 fixed
)
-
条件:当一个元素的
position
属性设置为absolute
或fixed
时,它会形成一个新的 BFC。 - 解释:绝对定位和固定定位的元素从普通流中完全脱离出来,它们不再受父元素的影响,因此需要创建一个新的 BFC 来管理它们的布局。
4. display
为某些特定值
-
条件:当一个元素的
display
属性设置为以下值时,它会形成一个新的 BFC:inline-block
table-cell
table-caption
flex
inline-flex
grid
inline-grid
-
flow-root
(CSS 新增的值,专门用于创建 BFC)
-
解释:这些
display
值会改变元素的默认布局行为,创建一个新的 BFC 来管理其内部内容的布局。
5. overflow
不为 visible
-
条件:当一个元素的
overflow
属性设置为hidden
、auto
或scroll
时,它会形成一个新的 BFC。 -
解释:通过设置
overflow
,浏览器会创建一个新的 BFC 来确保容器能够正确包裹其内部的浮动元素或溢出的内容,防止高度坍塌等问题。
6. contain
属性
-
条件:当一个元素的
contain
属性设置为layout
、content
或paint
时,它会形成一个新的 BFC。 -
解释:
contain
属性用于优化布局、样式和绘制,帮助浏览器更高效地处理复杂的页面结构。contain: layout
会创建一个新的 BFC,确保该元素的布局不会受到外部元素的影响。
7. 多列布局(column-count
或 column-width
)
-
条件:当一个元素使用了多列布局(
column-count
或column-width
)时,它会形成一个新的 BFC。 - 解释:多列布局会将内容分成多个列,为了确保每一列的内容不会相互干扰,浏览器会为多列容器创建一个新的 BFC。
8. writing-mode
为 vertical-rl
-
条件:当一个元素的
writing-mode
属性设置为vertical-rl
时,它会形成一个新的 BFC。 -
解释:
writing-mode
用于控制文本的书写方向,vertical-rl
表示从右到左的垂直书写模式。为了适应这种特殊的书写方式,浏览器会为该元素创建一个新的 BFC。
9. will-change
属性
-
条件:当一个元素的
will-change
属性指定了可能会发生变化的属性时,浏览器可能会为该元素创建一个新的 BFC,以优化性能。 -
解释:
will-change
提示浏览器提前为某些属性的变化做好准备,虽然它不一定总是创建 BFC,但在某些情况下确实会触发 BFC 的创建。
10. transform
或 filter
属性
-
条件:当一个元素应用了
transform
或filter
属性时,浏览器可能会为该元素创建一个新的 BFC,以确保其渲染效果不会影响其他元素。 -
解释:
transform
和filter
会创建一个新的堆叠上下文(stacking context),并且在某些情况下也会触发 BFC 的创建。
总结
形成 BFC 的条件多种多样,主要包括浮动、绝对定位、特定的 display
值、overflow
设置等。理解这些条件可以帮助开发者更好地控制页面布局,避免常见的布局问题,如浮动元素导致的高度坍塌、外边距折叠等。通过合理使用 BFC,可以创建更加稳定和可控的布局结构。
常见应用场景
-
清除浮动:通过设置
overflow: hidden;
或display: flow-root;
,可以创建一个新的 BFC,从而确保父容器能够正确包裹浮动的子元素,防止高度坍塌。 - 防止外边距折叠:通过创建 BFC,可以阻止相邻块级元素之间的垂直外边距发生折叠,确保布局的稳定性。
- 隔离浮动的影响:通过创建 BFC,可以确保某个容器内的浮动元素不会影响外部的非浮动元素,也不会被外部的浮动元素影响。
- 创建独立的布局区域:通过创建 BFC,可以将某些部分的布局与其他部分隔离开来,使得布局更加模块化和易于管理。