04你认真学了css?BFC+边距合并

一、BFC

1、定义:

先给一个官方的定义:(可能会看不懂我也不懂)

Formatting context(格式化上下文)是W3CCSS2.1规范中的一个概念。每个渲染区域用formattingContext表示,它是页面中的一块渲染区域,并且有一套渲染规则。它决定了其子元素将如何定位,以及和其他元素的关系和相互作用

再看下面这个定义:(一点点懂)

BFC(Block FormattingContext),块级格式化上下文。相当于制定一种如BFC这样的规则,在普通流中按照该规则进行布局。

在正常流中的盒子要么属于块级格式化上下文(BFC),要么属于内联格式化上下文,即块级元素在页面渲染的时候遵循怎么样的规则,它们之间有怎么样的作用。

再看这个:(还是一点点懂)

具有 BFC 特性的元素可以看作是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素,并且BFC具有普通容器所没有的一些特性。通俗一点来讲,可以把 BFC理解为一个封闭的大箱子,箱子内部的元素无论如何翻江倒海,都不会影响到外部。

总结:BFC没有定义,只有功能或特性

2、BFC会在哪里产生(官方的)

只要元素满足下面任一条件即可触发 BFC 特性
(1)body根元素
html里的根元素产生相应的“块级格式化上下文”这类的规则,如某些规则:块级容器可以充满父容器,父容器可以被子元素撑开,外边距产生合并,渲染顺序是从上到下(同一个块级格式化上下文中相邻块级盒之间的竖直margin会合并)
(2)浮动元素:float除了none以外的值;
float:left;该元素属性本身也产生了相应的块级格式化上下文。该元素产生的BFC与所在的根元素的BFC互不影响,此元素的作用域,则为该元素服务,与根元素产生一个隐形的边界
(3)绝对定位元素:positionabsolutefixed
(4)displayinline-block(非块盒的块容器), flex, 或inline-flex
(5)overflow除了visible以外的值(hiddenautoscroll

3、应用

这里的例子截取自该文章:10 分钟理解 BFC 原理
(1)功能1
让两个相邻的元素界限分明(同一个 BFC 下外边距会发生重叠或合并)

代码如下:

1
2
3
4
5
6
7
8
9
10
11
<head>
div{
width: 100px;
height: 100px;
background: lightblue;
margin: 100px;
}
</head>

<div></div>
<div></div>

从效果上看,因为两个 div 元素都处于同一个 BFC 容器下 (这里指 body 元素) 所以第一个 div的下边距和第二个div的上边距发生了重叠,所以两个盒子之间距离只有100px,而不是 200px。
如图:image
首先这不是 CSS 的bug,我们可以理解为一种规范。如果想要避免外边距的重叠,可以将其放在不同的 BFC 容器中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 <div class="container">
<p></p>
</div>
<div class="container">
<p></p>
</div>

<style>
.container {
overflow: hidden; ✔️
}
p {
width: 100px;
height: 100px;
background: lightblue;
margin: 100px;
}
</style>

这时候,两个盒子边距就变成了 200px ,
如图:image

(2)功能2
子元素被父元素包裹起来(BFC可以包含浮动的元素)(可代替clearfix来清除浮动)

  • display:flow-root; 让当前元素触发BFC(正交,考虑浏览器兼容)
  • overflow:hidden; 将溢出隐藏浮动的元素会脱离普通文档流,
    来看下下面一个例子,代码如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <style>
    .father{
    border: 1px solid #000;
    }
    .son{
    width: 100px;
    height: 100px;
    background: #eee;
    float: left;
    }
    </style>

    <div class=father>
    <div class=son></div>
    </div>

image

由于父元素(father)内子元素(son)进行浮动,脱离了“父亲”的文档流,所以容器只剩下 2px 的边距高度。此时可以触发容器的 BFC,那么“father”就可以包裹住“son”出去的浮动元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<style>
.father{
border: 1px solid #000;
overflow:hidden; ✔️
}
.son{
width: 100px;
height: 100px;
background: #eee;
float: left; ✔️
}
</style>

<div class=father>
<div class=son></div>
</div>

image

(3)功能3
BFC 可以阻止元素被浮动元素覆盖。先来看一个文字环绕效果,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<style>
.box1{
height: 100px;
width: 100px;
float: left;
background: lightblue;
}
.box2{
width: 200px;
height: 200px;
background: #eee;
}
</style>

<div class=box1>我是一个左浮动的元素</div>
<div class=box2>我是一个没有设置浮动, 也没有触发 BFC 元素, width: 200px; height:200px; background: #eee;</div>

image

此时,浮动元素浮在第二个元素上,第二个元素有部分区域被浮动元素所覆盖(但文本信息不会被浮动元素所覆盖) 。如果想避免元素被覆盖,可触第二个元素的 BFC 特性,在第二个元素中加入overflow:hidden;或者display:flow-root;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<style>
.box1{
height: 100px;
width: 100px;
float: left; ✔️
background: lightblue;
}

.box2{
width: 200px;
height: 200px;
background: #eee;
overflow:hidden; ✔️
/*或 display: flow-root; */ ✔️
}
</style>

<div class=box1>
我是一个左浮动的元素
</div>
<div class=box2>
我是一个没有设置浮动, 也没有触发 BFC 元素, width: 200px; height:200px; background: #eee;
</div>

就会变成:BFC 浮动处理
image
用来实现两列自适应布局:即左边宽度固定,如果想右边的内容自适应宽度,可以去掉上面右边内容的宽度(如果右边定宽,窄页面时,则会自动换到下一行排列)

二、边距合并

1、讲例子

案例1:
当实际中希望#headerh1之间产生一点缝隙(或间距),即使将h1设置 margin:50px; ,作为块级元素的h1margin左右生效,而上下则是#header+h1整体向下移动50px
这便是,外边距合并
image

案例2:
image
看案例似乎是<h1><p>标签所设置的外边距各30px,两者之间的间距理论来讲应该是60px,但事实上这是两个相邻元素的外边距产生合并,下边距<margiin-bottom>和上边距<margin-top>合并之后取较大值,这里为30px
这也是,外边距合并

2、合并场景

(1)相邻元素合并
同案例2
(2)父子合并
h1header,或者再嵌套元素或者与其的祖先元素嵌套,均能产生外边距合并,这些都能称之为“父子合并” ,如图:
image
(3)自己合并
如图,块级元素合并,无默认样式即靠在一起;含有p标签(含内容)的块级元素,则有默认上下margin,所以detailfooter则会产生缝隙(或间距)
image
image

.footer元素为空内容,设置 margin:30px; ,即说明上边距和下边距合并后的外边距总值是60px,不过.footer元素为空内容,所以页面效果仍然呈现30px,说明css元素中外边距合并的另一种情况:

自己和自己合并: 如图:image

三、取消合并(如何去解决外边距合并?)

1、边框、padding

存在于父子合并

为何#headerh1能够产生合并?即#header没有borderpadding(即一个可与外界隔离的边界线),导致h1自带的一个margin,冲出该边界,与#header合并

尝试在#header里添加边框(图1)或者加padding(内边距)(图2),让#headerh1margin-top,内外分开,即能做到不让外边距合并,如图:
图1
图2

2、BFC

如何让一个元素生成bfc?bfc可认为是拥有一片独立的空间,和其他的空间(或其他的文档流)区别开。注:添加bfc元素属性,可以取消合并有可能产生副作用
(1)父子元素不产生合并
A、添加:overflow:hidden;
image
B、添加 :float:left;
image
C、添加: display:inline-block;
image
D、添加: position:absolute;
image

(2)相邻元素不产生合并
A、添加:浮动元素
image
B、添加:overflow:hidden;
生成BFC,相当于生成了一个边界,即边框作为一个边界,有了边界之后,#header+h1父子元素便不能冲破该边界,自然与#detail元素的不产生合并.
image

【重点】: 而相邻元素之间的margin,可以认为不是该父子元素边界内,同样会产生合并。通常处理相邻元素之间的间距合并问题(除浮动外,浮动时不会被合并),即不考虑合并问题,直接设置为:margin-top:___px;

-------------本文结束感谢您的阅读-------------