盒模型和BFC

盒模型

什么是盒模型

我们在浏览器中所看到的的网页,事实上都是由一个一个的“块”来构成,我们可以把他称之为“盒子”,在css中,所有的元素都可以被看做是“盒子”,这种由一个个“盒子”堆叠起来的算法模型,我们称之为“盒模型”(Box Model)。

盒模型的构成

盒模型由四个部分组成,从外到内依次是:

  • margin(外边距)
  • border (边框)
  • padding (内边距)
  • content (内容)
css盒模型

盒模型的类型

在当下,我们有两种盒模型:

  • 标准盒子模型
  • 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的那个margin20px被完全覆盖在了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参与。他规定了这个区域内部的渲染规则,并且和这个区域外部毫不相干。
那么他是怎么规定他内部的渲染规则的呢?

  1. 内部box会在垂直方向一个接一个的摆放。
  2. 垂直方向上的距离由margin来决定,并且同一个BFC的两个相邻box的margin会发生重叠。(这就是我们前面讲到的margin合并)
  3. BFC内与外部独立,里面元素变化不会影响外面,反之亦然。
  4. BFC内元素不会与浮动元素发生重叠。
  5. 计算高度时,浮动元素也会参与。
    那么怎么样可以创建一个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来清除浮动实现:

  1. 通过<br/>元素的clear:both属性:
        <div class="div1">
            <div class="div2"></div>
            <br/>
        </div>
br{
    clear:both;
}
  1. 通过:afterclear: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属性一开始并不是为了布局而存在的属性,而是为了解决文字环绕而出现的,所以在文字方面他处理的比布局要好的多的多。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容