Webcourse/06-前端基础/02-CSS盒模型的深度思考及BFC.md
2018-03-07 17:08:42 +08:00

11 KiB
Raw Blame History

本文最初发表于博客园,并在GitHub上持续更新前端的系列文章。欢迎在GitHub上关注我一起入门和进阶前端。

以下是正文。

题目谈一谈你对CSS盒模型的认识

专业的面试,一定会问 CSS 盒模型。对于这个题目,我们要回答一下几个方面:

1基本概念content、padding、margin。

2标准盒模型、IE盒模型的区别。不要漏说了IE盒模型通过这个问题可以筛选一部分人。

3CSS如何设置这两种模型如何设置某个盒子为其中一个模型如果回答了上面的第二条还会继续追问这一条。

4JS如何设置、获取盒模型对应的宽和高这一步已经有很多人答不上来了。

5实例题根据盒模型解释边距重叠

前四个方面是逐渐递增,第五个方面,却鲜有人知。

6BFC边距重叠解决方案或IFC。

如果能回答第五条就会引出第六条。BFC是面试频率较高的。

总结以上几点从上到下知识点逐渐递增知识面从理论、CSS、JS又回到CSS理论。

接下来,我们把上面的六条,依次讲解。

标准盒模型和IE盒子模型

标准盒子模型:

IE盒子模型

上图显示:

在 CSS 盒子模型 (Box Model) 规定了元素处理元素的几种方式:

  • width和height内容的宽度、高度(不是盒子的宽度、高度)。
  • padding内边距。
  • border边框。
  • margin外边距。

CSS盒模型和IE盒模型的区别

  • 标准盒子模型中,width 和 height 指的是内容区域的宽度和高度。增加内边距、边框和外边距不会影响内容区域的尺寸,但是会增加元素框的总尺寸。

  • IE盒子模型中,width 和 height 指的是内容区域+border+padding的宽度和高度。

CSS如何设置这两种模型

代码如下:

    /* 设置当前盒子为 标准盒模型(默认) */
    box-sizing: content-box;

    /* 设置当前盒子为 IE盒模型 */
    box-sizing: border-box;

备注:盒子默认为标准盒模型。

JS如何设置、获取盒模型对应的宽和高

方式一通过DOM节点的 style 样式获取

	element.style.width/height;

缺点:通过这种方式,只能获取行内样式,不能获取内嵌的样式和外链的样式。

这种方式有局限性,但应该了解。

方式二IE独有的

	element.currentStyle.width/height;

获取到的即时运行完之后的宽高三种css样式都可以获取。但这种方式只有IE独有。

方式三(通用型)

	window.getComputedStyle(element).width/height;

方式三和方式二一样。只不过,方式三能兼容 Chrome、火狐。是通用型方式。

方式4

	element.getBoundingClientRect().width/height;

此 api 的作用是:获取一个元素的绝对位置。绝对位置是视窗 viewport 左上角的绝对位置。

此 api 可以拿到四个属性left、top、width、height。

总结:

上面的四种方式,要求能说出来区别,以及哪个的通用型更强。

margin塌陷/margin重叠

标准文档流中竖直方向的margin不叠加只取较大的值作为margin(水平方向的margin是可以叠加的即水平方向没有塌陷现象)。

PS如果不在标准流比如盒子都浮动了那么两个盒子之间是没有margin重叠的现象的。

我们来看几个例子。

兄弟元素之间

如下图所示:

子元素和父元素之间

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>

        * {
            margin: 0;
            padding: 0;
        }

        .father {
            background: green;

        }

        /* 给儿子设置margin-top为10像素 */
        .son {
            height: 100px;
            margin-top: 10px;
            background: red;
        }

    </style>
</head>
<body>
<div class="father">
    <div class="son"></div>
</div>
</body>
</html>

上面的代码中儿子的height是 100pxmagin-top 是10px。注意此时父亲的 height 是100而不是110。因为儿子和父亲在竖直方向上共一个margin。

儿子这个盒子:

父亲这个盒子:

上方代码中,如果我们给父亲设置一个属性:overflow: hidden就可以避免这个问题此时父亲的高度是110px这个用到的就是BFC下一段讲解

善于使用父亲的padding而不是儿子的margin

其实这一小段讲的内容与上一小段相同都是讲父子之间的margin重叠。

我们来看一个奇怪的现象。现在有下面这样一个结构div中放一个p

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

上面的结构中,我们尝试通过给儿子p一个margin-top:50px;的属性让其与父亲保持50px的上边距。结果却看到了下面的奇怪的现象

此时我们给父亲div加一个border属性就正常了

如果父亲没有border那么儿子的margin实际上踹的是“流”踹的是这“行”。所以父亲整体也掉下来了。

margin这个属性本质上描述的是兄弟和兄弟之间的距离 最好不要用这个marign表达父子之间的距离。

所以如果要表达父子之间的距离我们一定要善于使用父亲的padding而不是儿子的margin。

BFC边距重叠解决方案

BFC的概念

BFCBlock Formatting Context块级格式化上下文。你可以把它理解成一个独立的区域。

另外还有个概念叫IFC。不过BFC问得更多。

BFC 的原理/BFC的布局规则【非常重要】

BFC 的原理,其实也就是 BFC 的渲染规则(能说出以下四点就够了)。包括:

  • 1BFC 里面的元素,在垂直方向,边距会发生重叠

  • 2BFC在页面中是独立的容器外面的元素不会影响里面的元素反之亦然。稍后看举例1

  • 3BFC区域不与旁边的float box区域重叠。(可以用来清除浮动带来的影响)。(稍后看举例2

  • 4计算BFC的高度时浮动的子元素也参与计算。稍后看举例3

如何生成BFC

有以下几种方法:

  • 方法1overflow: 不为vidible可以让属性是 hidden、auto。【最常用】

  • 方法2浮动中float的属性值不为none。意思是只要设置了浮动当前元素就创建了BFC。

  • 方法3定位中只要posiiton的值不是 static或者是relative即可可以是absolutefixed也就生成了一个BFC。

  • 方法4display为inline-block, table-cell, table-caption, flex, inline-flex

参考链接:

下面来看几个例子看看如何生成BFC。

BFC 的应用

**举例1**解决 margin 重叠

当父元素和子元素发生 margin 重叠时,解决办法:给子元素增加一个父元素给这个父元素创建BFC

比如说,针对下面这样一个 div 结构:

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

上面的div结构中如果父元素和子元素发生margin重叠我们可以给子元素创建一个 BFC就解决了

<div class="father">
    <p class="son" style="overflow: hidden">
    </p>
</div>

因为第二条BFC区域是一个独立的区域不会影响外面的元素

举例2BFC区域不与float区域重叠

针对下面这样一个div结构

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>

        .father-layout {
            background: pink;
        }

        .father-layout .left {
            float: left;
            width: 100px;
            height: 100px;
            background: green;
        }

        .father-layout .right {
            height: 150px;  /*右侧标准流里的元素,比左侧浮动的元素要高*/
            background: red;
        }

    </style>
</head>
<body>

<section class="father-layout">
    <div class="left">
        左侧,生命壹号
    </div>
    <div class="right">
        右侧smyhvaesmyhvaesmyhvaesmyhvaesmyhvaesmyhvaesmyhvaesmyhvaesmyhvaesmyhvaesmyhvaesmyhvae
    </div>
</section>

</body>
</html>

效果如下:

上图中,由于右侧标准流里的元素,比左侧浮动的元素要高,导致右侧有一部分会跑到左边的下面去。

如果要解决这个问题可以将右侧的元素创建BFC,因为第三条BFC区域不与float box区域重叠。解决办法如下将right区域添加overflow属性

    <div class="right" style="overflow: hidden">
        右侧smyhvaesmyhvaesmyhvaesmyhvaesmyhvaesmyhvaesmyhvaesmyhvaesmyhvaesmyhvaesmyhvaesmyhvae
    </div>

上图表明,解决之后,father-layout的背景色显现出来了,说明问题解决了。

**举例3**清除浮动

现在有下面这样的结构:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>

        .father {
            background: pink;
        }

        .son {
            float: left;
            background: green;
        }

    </style>
</head>
<body>

<section class="father">
    <div class="son">
        生命壹号
    </div>

</section>
</body>
</html>

效果如下:

上面的代码中儿子浮动了但由于父亲没有设置高度导致看不到父亲的背景色此时父亲的高度为0。正所谓有高度的盒子,才能关住浮动

如果想要清除浮动带来的影响,方法一是给父亲设置高度,然后采用隔墙法。方法二是 BFC给父亲增加 overflow=hidden属性即可, 增加之后,效果如下:

为什么父元素成为BFC之后就有了高度呢这就回到了第四条计算BFC的高度时浮动元素也参与计算。意思是,在计算BFC的高度时子元素的float box也会参与计算

我的公众号

想学习代码之外的软技能?不妨关注我的微信公众号:生命团队idvitateam)。

扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外: