likes
comments
collection
share

浮动与BFC容器

作者站长头像
站长
· 阅读数 20

浮动布局是面试中的一个考点,且大多数面试官在考你css时,问的最多的知识点就是浮动,所以我们不仅要会用浮动去布置页面,还要深入理解其原因,知其然,又要知其所以然,只有这样,你才能在面试官面前如鱼得水般的谈笑自如。下面我会引导你去理解浮动布局究竟有啥知识点和细节需要去理解和注意。

一, 浮动特点

1. 实现文字环绕效果和脱离文档流

在以前的网站上,有着这么一种典型布局方式(文字环绕图片),如图:

浮动与BFC容器

你写着写着,突然想插入一张图片,然后图片后面继续写字,这时你怎么做?没错,你想的没错,由此浮动布局就产生了。

看如下代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
    img{
        width: 100px;
    }
</style>
<body>
    <div class="box">
        <img src="https://t7.baidu.com/it/u=1595072465,3644073269&fm=193&f=GIF" alt="">
        <p>昨天晚上,我在家里看书。忽然,一只蝴蝶飞过我的头上,我想:等它飞倦了,停下来的时候,我得仔细地看一看它。蝴蝶飞了几分钟,终于停到我写字的书桌旁边。啊,是一只漂亮的花蝴蝶,一对色彩斑斓的翅膀、两根触角在头上轻轻摆动、它的肚子时而鼓时而收缩,我知道此时花蝴蝶一定在也在看着我!好像在向着我诉说今天飞行的快乐!原来,生命的意义在于你是否有一颗快乐的心、是否能够坚强地战胜生活!
</p>
    </div>
</body>
</html>

运行后如下图:

浮动与BFC容器

因为p是块级标签,他会霸占一行,所以文字并没有和图片放在同一行,而是另起一行。

现在我们要使文字和图片放一起,即文字环绕图片,看如下css中img修改部分代码:

img{
    width: 100px;
    float: left;  // 向左浮动
}

运行如下图:

浮动与BFC容器

可以看到确实已经实现了文字环绕图片效果,我们再来检查一下网页,看如下图:

浮动与BFC容器

我们发现img和p容器重叠了,正常情况下,容器是不会重叠的,如果重叠了,那么只有一种情况:某个容器脱离了文档流。浮动使p标签脱离了文档流,但是我们会产生一个疑问,既然是容器重叠,为什么图片没有盖住p标签里面的文字。(这里有人可能不理解什么是脱离文档流,不用急,后面我会举例子)

我们来看另外一个也可以脱离文档流的例子,将css中的img修改如下:

img{
    width: 100px;
    position: absolute;
}

运行后:

浮动与BFC容器

我们发现容器重叠了,说明有容器脱离了文档流,但是图片盖住了文字,我们就会产生疑问,都是脱离文档流,为什么浮动可以环绕文字,而绝对定位却不能?没有太多的道理,因为,当年就是为了使文字环绕图片而创造的浮动

我做这个对比,是要让你更加的清楚浮动的两个特点:实现文字环绕效果脱离文档流

注意:浮动只有向左浮动float: left;和向右浮动float: right;,没有什么向上向下浮动

2. 可以让块级元素水平排列

看如下例子:

<!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>
    li {
      list-style: none;
    }
    .item{
      width: 200px;
      height: 50px;
      /* display: inline-block; */
      /* float: left; */
    }
    .item:first-child{
      background-color: red;
    }
    .item:nth-child(2){
      background-color: blue;
    }
    .item:last-child{
      background-color: green;
    }
  </style>
</head>
<body>
  <ul>
    <li class="item">1</li>
    <li class="item">2</li>
    <li class="item">3</li>
  </ul>
</body>
</html>

运行如图:

浮动与BFC容器

(1)设置行内块

现在我们想把这三个长方形水平排列,于是我们想到了在css中的item中用display: inline-block; 把块级元素li设置为行内块元素,这样他们三个就能水平排列,得到如下图:

浮动与BFC容器 但我们发现他们之间有间距,我们也没有设置外边距,难道是默认自带的边距吗?于是我们又检查了网页,发现标签并没有带边距......

其实这是一个小坑,在html里,代码的换行也会被识别成空格,上面产生间距的根本原因就是你的三个li标签换行了,你把它们全部放在一行里,间距就消失了,不信你可以试试。

那对于这种情况我们怎么解决,总不能不换行吧,你要是真这样做,那等着被人打死吧(开玩笑),正常写代码肯定要换行的。

你可以这样做:在css里设置ul{font-size: 0;},li{fontsize: 20px;}在ul里设置字符大小,就是让ul里的字符大小为0,空格也属于字符,所以就能消除换行被识别成空格的影响。又在li里设置字符大小20px,是因为,你不想li里的字符消失。这时,你可能会问,设置两个字符大小,到底听谁的,同时设置了两个字符大小,根据就近原则,li标签里字符大小为20px。

(2)浮动

要想三个长方体水平排列,还可以使用浮动,直接在css中的item里设置向左浮动float: left;得到如下图:

浮动与BFC容器

相比于上一种将块级元素设置为行内块元素的方法,这种就没那么多的问题,简单清晰明了。

如果你还想设置间距,直接使用margin设置,但这里又有一个坑,浮动元素可以用 marign, 但是不能使用 margin: 0 auto;,你可以试一试看看有没有变化,结果一定是没有变化的。(这个问题,我的一个学长被面试官坑了),

接下来我还要讲一个细节,在上面我们设置了浮动,使块级元素水平排列后,运行后我们来检查一下网页,如下图:

浮动与BFC容器 看这张我做标记的图片,发现ul容器的高度为0,不对呀,按道理来说,子容器li有高度,它会将父容器ul的高度撑起来,高度不应该是0。

解释:浮动具有脱离文档流的特点,它会将设置浮动的容器脱离文档流,简单点理解就是:与原来的容器不在一层中,自然也就不会影响不在同一层中的容器了。在上面li设置为了浮动,li脱离了文档流,那么自然就不会将父容器ul的高度撑起,ul也没有设置高度,那么ul高度自然为0,我们称这种情况为父容器塌陷

看到这里你也就能够理解脱离文档流是什么意思了。

二,浮动带来的困扰与清除浮动

1. 困扰

<!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>
    li {
      list-style: none;
    }
    .item{
      width: 200px;
      height: 50px;
      float: left;
    }
    .item:first-child{
      background-color: red;
    }
    .item:nth-child(2){
      background-color: blue;
    }
    .item:last-child{
      background-color: green;
    }
  </style>
</head>
<body>
  <ul>
    <li class="item">1</li>
    <li class="item">2</li>
    <li class="item">3</li>
  </ul>
  <div class="title">这是正文。。。。</div>
</body>
</html>

运行结果:

浮动与BFC容器 我们可以看到,因为浮动导致父容器塌陷,所以后面的容器出现在第一行后面,但有时候布局时,我们不想让后面的容器内容一直排在第一行,所以为了不影响后面容器的布局,这个时候就需要清除浮动了。

2. 清除浮动一般有5种方法

(1)设置父元素高度。

我们仔细想了下,出现上面这种困扰主要是父容器塌陷了,那么如果我们专门设置父容器高度去抵消塌陷的问题,那是不是就解决问题了。css中加入ul{height: 50px;},你可以加上去试试。

缺点:极其不优雅,这样做,相当于写死了高度,以后要改的话很麻烦。

(2)在父元素结束之前添加一个空元素,并设置 clear: both;

<ul>
    <li class="item">1</li>
    <li class="item">2</li>
    <li class="item">3</li>
    <!--html增加的部分-->
    <div class="clear"></div>
</ul>

/* css增加的部分 */
.title{
      clear: both;
}

clear: both;是清除了左边和右边的浮动,要是你想单独清除左边或者右边,将both改为leftright

缺点:如果有100个浮动,那么就需要建100个空元素,增加负担,且增加了100行代码,极其不优雅。

(3)借助伪元素 ::after 清除浮动

/* css中加入 */
ul::after{
      content: '';
      clear: both;
      display: block;
    }

伪元素只有befor和after,这里不能写befor,是因为用完浮动后才清除浮动,而不是还没开始浮动就清除浮动了。如果你加入这段代码,运行检查网页,你就能看到一段代码在这样的位置,如下图:

浮动与BFC容器 看到这段代码,你就会感觉这和第二种方法有着异曲同工之妙,最大的不同是,当有100个浮动时,你不需要创建100个空元素,只需要在每个浮动的父元素上添加同一个类名,然后将上面的ul换成这个类名,你就能清除这100个浮动了。

经常用的方法,也是最好用

(4)把父容器设置成 BFC 容器

把ul设置为BFC容器,css中加入ul{overflow: hidden;},你可能不知道bfc容器是什么,没关系,后面我会详细解释,先放这。

这个也经常使用

(5)给后面受影响的元素设置 clear: both;

/* css中加入 */
.title{
    clear: both;
}

受影响的元素是title,所以直接给它清除浮动。

缺点:最好别用,你自己检查网页,会发现布局很乱,但是确实可以达到清除浮动的效果。

三,BFC

1. BFC的介绍与引导

Block Formatting Context 的简称

译为:块级格式化上下文

直接上例子引导你理解BFC,

<!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>
        *{
            margin: 0;
            padding: 0;
        }
        .wrap {
            height: 500px;
            background-color: aqua;
            margin-top: 100px;
        }
        .box {
            height: 200px;
            background-color: #8d3030;
            /* margin-top: 50px; */
        }
    </style>
</head>
<body>
    <div class="wrap">
        <div class="box"></div>
    </div>
</body>
</html>

运行后你的界面应该是这样的:

浮动与BFC容器

我们再添加代码,css中的box加入margin-top: 50px;,这个时候你再捋一下思路,想象一下运行后的画面是什么样的,你的画面应该是这样的:

浮动与BFC容器 但运行后却不是,因为子容器box会带着父容器wrap距离顶部往下移,而不是以父容器wrap为参考对象往下移。我们称这种现象为margin重叠。(注意:margin重叠只发生在上下,不发生在左右,大家可以动手试试)

这不是你的错,这就是个bug,因此我们需要方法去解决这个bug,而BFC容器就是解决像这样的问题而产生的,那它是怎么解决的呢?下面我会介绍他的规则,看完后,你就会明白。

2. BFC布局规则

(1)内部的Box会在垂直方向,一个接一个地放置

<!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>
        *{
            margin: 0;
            padding: 0;
        }
        ul{
            overflow: hidden;  // 触发BFC
        }
    </style>
</head>
<body>
    <div class="box">
        <ul>
            <li style="width: 200px;height: 50px;background-color: blue;">1</li>
            <li style="width: 200px;height: 50px;background-color: red;">2</li>
        </ul>
    </div>
</body>
</html>

浮动与BFC容器 运行后,因为overflow: hidden;触发了BFC,可以看到BFC内部的东西确实是在垂直方向上一个接着一个放置。

(2)bfc容器内部和外部的容器相互隔离,互不影响 --- 解决margin重叠问题

就因为这个规则,我们在上面引导例子中的margin重叠问题就可以很快解决,直接把父元素wrap设置为BFC容器(加上代码:overflow: hidden;),运行后就是你想象中的样子了: 浮动与BFC容器

(3)bfc容器内,在垂直方向上相邻元素的margin会重叠

看代码比较好理解:

<!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>
        *{
            margin: 0;
            padding: 0;
        }
        ul{
            overflow: hidden;
            margin-top: 100px;
            background: #302222;
        }
        li{
            margin: 50px;
        }
    </style>
</head>
<body>
    <div class="box">
        <ul>
            <li style="width: 200px;height: 50px;background-color: blue;">1</li>
            <li style="width: 200px;height: 50px;background-color: red;">2</li>
        </ul>
    </div>
</body>
</html>

浮动与BFC容器 我们可以看到第一个长方形和第二个长方形间距只有50px,两个元素我们都设置为margin: 50px;,加起来应该有100px,但这里只有50px,看图很容易就知道margin重叠了,这种情况只有在垂直方向上会有,水平方向上的相邻元素不会发生margin重叠。(这里可以说它是问题,也可以说它不是问题,关键在于怎么看)

(4)bfc容器在计算高度时,浮动元素也参与计算 --- 清除浮动

正因为 bfc 容器会把浮动元素的高度也计算在里面,因此就能解决父容器塌陷后高度为 0 所产生的问题。它也是清除浮动的一种方法。(注意:bfc只会把浮动元素的高度计算在内,并不会把脱离文档流元素高度计算在内,例如:绝对定位absolute也会脱离文档流,但不会被bfc计算在内。

3. 触发BFC

下面的这些都会触发BFC,我就不一一举例解释说明了,大家自行探索。

  1. overflow: hidden || auto || overlay || scroll
  2. flaot: left || right
  3. position: absolute || fixed
  4. display: inlne-block
  5. disaplay: table-cell || table-xxx
  6. disaplay: flex || inlne-flex
转载自:https://juejin.cn/post/7365152703829262374
评论
请登录