当年学的不清不楚的知识点:外边距重叠与BFC
外边距重叠
mdn: 区块的上下外边距有时会合并(折叠)为单个边距,其大小为两个边距中的最大值(或如果它们相等,则仅为其中一个),这种行为称为外边距折叠。
典型的外边距重叠的三种情况:
相邻兄弟元素的垂直外边距重叠
当两个相邻的块级兄弟元素的上下外边距相遇时,较大的外边距会覆盖较小的外边距,而不是将两者相加。
<div class="box1"></div>
<div class="box2"></div>
.box1 {
margin-bottom: 50px;
background-color: lightblue;
height: 100px;
}
.box2 {
margin-top: 30px;
background-color: lightgreen;
height: 100px;
}
结果:两者的间距为50px,取较大的外边距,而不是50px + 30px = 80px。
父子元素的垂直外边距重叠
如果没有设定边框、内边距、行级内容,也没有创建区块格式化上下文或间隙来分隔块级元素的上边距与其内一个或多个子代块级元素的上边距(下边距也一样),则会出现这些外边距的折叠,重叠部分最终会溢出到父代元素的外面。
代码片段(一)
<div class="parent">
<div class="child"></div>
</div>
.parent {
background-color: lightgray;
margin-top: 30px;
}
.child {
background-color: lightblue;
margin-top: 50px;
height: 100px;
}
结果:parent的上外边距30px与child的上外边距50px重叠,实际显示的上边距是50px(取较大值)。
代码片段(二)
<div>
<p>我的下边距与我的父元素折叠,产生了一个 <code>1.2rem</code> 的边距。</p>
</div>
<p>我在上面元素的下方 <code>1.2rem</code> 处。</p>
div {
margin: 2rem 0 1.1rem;
background: lavender;
}
p {
margin: 0.4rem 0 1.2rem 0;
background: yellow;
}
-
div的上外边距(2rem)与其内部第一个子元素的上外边距(0.4rem)重叠,div距离顶部的距离为二者较大值(2rem)。
-
div的下外边距(1.1rem)与其内部子元素p的下外边距(1.2rem)也会重叠,其最终下外边距为1.2rem;而div与下一个兄弟元素的距离为1.2rem和兄弟元素上外边距(0.4rem)中的较大值(1.2rem)。
可以看到,div与p的下外边距发生了重叠,且p的下外边距溢出到了父代元素的外面。
即使某一外边距为 0,这些规则仍然适用。因此就算父元素的外边距是 0,第一个或最后一个子元素的外边距仍然会(根据上述规则)“溢出”到父元素的外面。
空的块级元素外边距重叠
如果块级元素没有设定边框、内边距、行级内容、高度、最小高度来分隔块级元素的上边距及其下边距,则会出现其上下外边距的折叠。
<div class="item"></div>
<div class="empty"></div>
<div class="box"></div>
.item {
margin-bottom: 30px;
height: 100px;
background-color: lightblue;
}
.empty {
margin: 30px 0 60px;
}
.box {
margin-top: 30px;
height: 100px;
background-color: lightblue;
}
通俗来讲,此时item和box的外边距为:empty元素上下外边距的最大值、item元素下外边距以及box元素的上外边距三者中的最大值。所以外边距为60px。
BFC
什么是BFC
区块格式化上下文(Block Formatting Context,BFC)是 Web 页面的可视 CSS 渲染的一部分,是块级盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。
可以将BFC看作是一个独立的布局环境,这个环境中物品按照一定的规则进行摆放,并且不会影响其他环境中的物品。
常见创建BFC的条件
- 文档的根元素(
<html>)。 - float值不为none的元素。
- 绝对定位元素(position值为absolute或fixed)。
- 行内块元素(inline-block).
- overflow值不为
visible或clip的块级元素。 - display值为
flow-root的元素。 - 弹性元素(
display值为flex或inline-flex元素的直接子元素)
BFC的作用
包含内部浮动
BFC使得让浮动内容和周围内容等高。也可以说成是:浮动子元素的高度不会被忽略。这样就可以避免出现高度塌陷问题。
这里就借助mdn的例子来理解:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
section {
height: 150px;
}
.box {
background-color: rgb(224, 206, 247);
border: 5px solid rebeccapurple;
}
.box[style] {
background-color: aliceblue;
border: 5px solid steelblue;
}
.float {
float: left;
width: 200px;
height: 100px;
background-color: rgba(255, 255, 255, 0.5);
border: 1px solid black;
padding: 10px;
}
</style>
</head>
<body>
<section>
<div class="box">
<div class="float">我是浮动的盒子!</div>
<p>我是容器内的内容。</p>
</div>
</section>
<section>
<div class="box" style="overflow:auto">
<div class="float">我是浮动的盒子!</div>
<p>我是 <code>overflow:auto</code> 容器内部的内容。</p>
</div>
</section>
<section>
<div class="box" style="display:flow-root">
<div class="float">我是浮动的盒子!</div>
<p>我是 <code>display:flow-root</code> 容器内部的内容。</p>
</div>
</section>
<!-- display:flex; 创建BFC -->
<section>
<div class="box" style="display:flex">
<div class="float">我是浮动的盒子!</div>
<p>我是 <code>display:flex</code> 容器内部的内容。</p>
</div>
</section>
<!-- display:inline-block; 行内块元素创建BFC -->
<section>
<div class="box" style="display:flex">
<div class="float">我是浮动的盒子!</div>
<p>我是 <code>display: inline-block</code> 容器内部的内容。</p>
</div>
</section>
</body>
</html>
对比后几个盒子和第一个盒子,可以看到创建BFC的容器高度会包含浮动元素的高度。
排除外部浮动
正常文档流中建立的 BFC 不得与元素本身所在的块格式化上下文中的任何浮动的外边距重叠。
通俗的说:BFC的区域不会与浮动元素发生重叠。利用这个属性我们可以用浮动配合BFC区域实现两栏布局。
<section>
<div class="float">试试重新调整这个外部浮动元素的大小</div>
<div class="box"><p>普通</p></div>
</section>
<section>
<div class="float">试试重新调整这个外部浮动元素的大小</div>
<div class="box" style="display:flow-root">
<p><code>display:flow-root</code></p>
<p></p>
</div>
</section>
这里的效果是拖动多行输入框的大小,使用display: flow-root创建BFC的右侧元素可以自适应宽度。
阻止外边距重叠
<div class="blue"></div>
<div class="red"></div>
.blue,
.red {
height: 50px;
margin: 10px 0;
}
.blue {
background: blue;
}
.red {
background: red;
}
这个示例中由于外边距重叠两个盒子间只有10px的间距。
如果我非要上边盒子提供10px,下边盒子提供10px这样的效果呢?
可以将第二个盒子包裹在另一个div里,使用overflow: hidden创建一个新的BFC,防止外边距重叠:
<div class="blue"></div>
<div class="outer">
<div class="red"></div>
</div>
.outer {
overflow: hidden;
background: transparent;
}
关于外边距还有几点需要注意:
- BFC内的元素存在垂直外边距重叠的情况
- BFC区域内的子元素外边距不会溢出父元素
- BFC区域与其兄弟元素会存在垂直外边距重叠的情况
个人思考
实现BFC的方法有多种,不同的方法适用于不同的场景。
- overflow属性
这是最常用的创建BFC的方法之一。
缺点:
- 如果子元素内容超出了父容器的宽度或高度,
overflow: hidden;会裁剪掉溢出的部分,可能导致内容不可见。这在某些情况下不是期望的行为。 - 使用
overflow: auto可能会遇到不希望出现的滚动条或阴影,需要注意。
display: flow-root(推荐)
一个新的 display 属性的值,它可以创建无副作用的 BFC。在父级块中使用 display: flow-root 可以创建新的 BFC。
老旧浏览器可能不支持该属性,因此在兼容性要求高的项目中需要考虑替代方案。
float: left | right
浮动元素自动触发BFC。这个方法感觉比较勉强,
缺点:
- 浮动会让元素脱离正常文档流,影响布局顺序和其他元素的位置,通常需要清除浮动的额外处理。
- 不适合布局控制。
...
欢迎大家阅读、指出错误!