盒模型
什么是盒模型
我们在浏览器中所看到的的网页,事实上都是由一个一个的“块”来构成,我们可以把他称之为“盒子”,在css中,所有的元素都可以被看做是“盒子”,这种由一个个“盒子”堆叠起来的算法模型,我们称之为“盒模型”(Box Model)。
盒模型的构成
盒模型由四个部分组成,从外到内依次是:
- margin(外边距)
- border (边框)
- padding (内边距)
- content (内容)
盒模型的类型
在当下,我们有两种盒模型:
- 标准盒子模型
- IE盒子模型
区别这两种盒子模型的方式,就是看其对于宽度(width
)和高度(height
)的定义中是否包含边框和内边距宽度。
在标准盒子模型中,宽度和高度就是指内容区域的宽高,而在IE盒子模型中的宽度和高度不仅仅包含内容区域,还包括了边框和内边距的宽度。
我们可以这样设置盒子模型的类别:
/* 设置为标准盒子模型(默认) */
box-sizing: content-box;
/* 设置为IE盒子模型 */
box-sizing: border-box;
margin的重叠(合并)与塌陷
margin重叠(合并)
这是一种非常常见的现象:
假设我们有两个div:
<body>
<div class="div1"></div>
<div class="div2"></div>
</body>
.div1{
width: 100px;height: 100px;
background-color: red;
margin-bottom: 20px;
}
.div2{
width: 100px;height: 100px;
background-color: green;
margin-top: 40px;
}
按照我们的设定,div1和div2之间的距离应该是20+40=60的距离,但是事实上,我们发现他们之间的margin
只有40px,也就是说,div1的那个margin
20px被完全覆盖在了40px的里面。
我们来概括一下:
处于上下位置关系的两个div容器,在通过margin-top、margin-bottom改变间距时,如果两个属性的值相同时,则两容器间的距离就是这个值;如果两个属性的值不同,则取较大值作为两容器间的距离,这种现象我们称之为是margin重叠。
在实际开发中我们并不需要解决这个问题,重点是下面的塌陷。
margin塌陷
<body>
<div class="div1">
<div class="div2"></div>
</div>
</body>
.div1{
width: 100px;height: 100px;
background-color: red;
}
.div2{
width: 50px;height: 50px;
background-color: green;
margin-top: 40px;
}
我们首先还是来看代码:
我们设置了内部的元素的margin为40px,按照我们的理解,应该是div2在div1内部下移40px,而事实上,我们看到div2就处于div1的顶部,而且带着div1从顶部下移了40px。
处于父子位置关系的两个div容器,在子元素通过margin-top属性时,并不会相对父级移动,而是会带着父级一起动,这种现象我们称之为是margin塌陷。
处理margin塌陷问题非常的简单,我们只需要触发父级容器的BFC。
BFC
什么是BFC
从上面的内容我们了解到盒子Box,是CSS布局的基本单位。而决定这些盒子怎么布局的,称之为格式上下文(Formatting context)。
不同类型的盒子会参与不同的格式化上下文,这里主要是两种:
-block-level box:display 属性为:block,list-item,table的元素,会生成 block-level box。并且参与Block Formatting Context
-inline-level box:display 属性为:inline,inline-block,inline-table的元素,会生成 inline-level box。并且参与Inline Formatting Context(行内格式化上下问,简称IFC)
我们这里主要讲第一种:
块级格式化上下文 (Block Formatting Context),简称BFC。它是一个独立的渲染区域,只有block-level box参与。他规定了这个区域内部的渲染规则,并且和这个区域外部毫不相干。
那么他是怎么规定他内部的渲染规则的呢?
- 内部box会在垂直方向一个接一个的摆放。
- 垂直方向上的距离由margin来决定,并且同一个BFC的两个相邻box的margin会发生重叠。(这就是我们前面讲到的margin合并)
- BFC内与外部独立,里面元素变化不会影响外面,反之亦然。
- BFC内元素不会与浮动元素发生重叠。
- 计算高度时,浮动元素也会参与。
那么怎么样可以创建一个BFC呢?有以下几个创建场景:
- body元素是一个BFC。
- 浮动元素是一个BFC(float除none以外)
- 绝对定位的元素是一个BFC(position的值为absolute或者fixed)
- display的值为flex,grid,flow-root
- overflow除visible以外的值(hidden、auto、scroll).
BFC能解决什么问题
我们首先当然还是用BFC来解决一下上面遇到的两个问题:
margin重叠的解决方案
两个不同BFC内的元素不会相互影响,所以我们只需要让他们处于两个不同的BFC中:
<body>
<div class="div1"></div>
<div style="overflow:hidden">
<div class="div2"></div>
</div>
</body>
margin塌陷的解决方案
解决起来非常简单,我们只要将div1设置为一个独立的BFC:
.div1 {
width: 100px;height: 100px;
background-color: red;
overflow: hidden;
}
这样就可以看到我们所想要看到的结果:
这有一个非常常用的名词,叫做清除内部浮动。
消除因浮动产生的元素塌陷
首先还是来看代码:
<body>
<div class="div1">
<div class="div2"></div>
</div>
</body>
.div1{
background-color: red;
}
.div2{
width: 100px;height: 100px;
background-color: green;
float: left;
}
这段代码在界面上的效果我们只能看到一个绿色的正方形,而看不到他红色的背景。
因为div1不是BFC所以他无法计算出浮动元素的高度,要解决这个问题我们只需要将div1设置为一个BFC。
.div1{
background-color: red;
overflow:hidden;
}
这里值得一提的是,要消除浮动的影响并不只是这么一种方法,还可以通过使用
clear:both
来清除浮动实现:
- 通过
<br/>
元素的clear:both
属性:
<div class="div1">
<div class="div2"></div>
<br/>
</div>
br{
clear:both;
}
- 通过
:after
的clear:both
属性(注意是加载div1不是div2):
.div1:after{
clear:both;
content:'';
display:block;
}
消除因浮动产生的元素重叠
我们来看看最后一种情况:
<body>
<div class="div1"></div>
<div class="div2"></div>
</body>
.div1{
width: 50px;height: 50px;
background-color: red;
float: left;
}
.div2{
width: 100px;height: 100px;
background-color: green;
}
我们看到div1和div2叠加到了一起,我们通过给非浮动元素添加一个BFC的方式来解决这个问题。
.div2{
width: 100px;height: 100px;
background-color: green;
overflow: hidden;
}
这样我们就能看到两个div正常显示了:
在这个例子中,值得注意的是文字并不会叠加,如果我们给div1和div2分别来点文字(在添加
overflow:hidden
之前):
<body>
<div class="div1">1</div>
<div class="div2">2</div>
</body>
我们看到的效果是这样的:
这是因为float属性一开始并不是为了布局而存在的属性,而是为了解决文字环绕而出现的,所以在文字方面他处理的比布局要好的多的多。