面试必考点:浮动布局和BFC,给你讲的明明白白

201 阅读7分钟

前言

清除浮动和BFC是前端面试经久不衰的考点,本文介绍了清除浮动的五种方式及适用性,还介绍了BFC容器的特性及触发方式,相信你认真阅读完面试肯定不在话下

浮动布局的特性

1. 实现文字环绕的效果

p为块级元素,img为行内元素。注意:float后面只能接两个值,leftright

<head>
    <title>Document</title>
    <style>
        img{
            width: 100px;
            float: left;  /* 向左浮动 */
        }
    </style>
</head>
<body>
    <img src="https://img0.baidu.com/it/u=46505623,3598573663&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500" alt="">
    <p>文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字
        文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字
        文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字文字
    </p>
</body>

7d43445895957ae0452fd73b67252fba.jpg

2.导致一个元素脱离文档流

看图,p标签元素与img元素重叠,说明img标签被加上浮动后已经脱离了文档流,从而影响了p标签元素的布局,它向前占据了原本img图片的文档流位置 image.png

3. 让块级元素水平排列

<head>
    <title>Document</title>
    <style>
        li{
            list-style: none;
            width: 200px;
            height: 50px;
            float: left;  /* 向左浮动 */
        }
        .item:first-child{
            background-color: red;
        }
        .item:nth-child(2){
            background-color: green;
        }
        .item:last-child{
            background-color: blue;
        }
    </style>
</head>
<body>
    <ul>
        <li class="item">1</li>
        <li class="item">2</li>
        <li class="item">3</li>
    </ul>    
</body>

7b26c4b7a16002c2dedc3b7856e586e7.jpg

让几个li元素水平排列还有一种方法就是:将li转换成行内块,不过这样会导致几个li元素之间有缝隙,因为HTML中代码的换行也会被识别为空格字符,对此的解决办法是可以给父容器ul加一个 font-size:0; 但同时li里面的字体也会消失

4. 可以使用margin,但不能使用margin: 0 auto;让浮动元素水平居中

想要浮动元素水平居中可以将父容器设置为弹性并使用 justify-content: center; 属性,或者使用定位、负边距等...

清除浮动

浮动会让li元素脱离文档流的同时,也会导致父容器ul没办法被子容器撑开,高度塌陷的问题,还会影响父元素的兄弟元素.title排版。

<body>
    <ul>
        <li class="item">1</li>
        <li class="item">2</li>
        <li class="item">3</li>
    </ul>    
    <div class="title">这是标题</div>
</body>

image.png

为了达到父元素高度不塌陷、其他元素不被影响的目的,接下来就要谈谈清除浮动方几种方式:

1. 设置父元素高度

假如元素高度已经被知晓且被定死,那么这种方式就可用。事实上,前端工程师大多数情况并不知道容器里面要放多少东西且会被撑到多大,所以直接设置父容器高度的方式很不优雅

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

在浮动元素的父容器末尾插入一个没有内容的块级元素。但这种方法也不建议,毕竟你有一百个浮动元素的时候你总不能添加一百行代码去放空元素吧,代码很冗余

</style>
    /* 其他样式省略 */
    .clear{
         clear: both;
     }
</style>
<body>
    <ul>
        <li class="item">1</li>
        <li class="item">2</li>
        <li class="item">3</li>
        <div class="clear"></div>
    </ul>    
    <div class="title">这是标题</div>
</body>

3. 利用伪元素::after

在浮动元素的父容器末尾添加伪元素,该伪元素转换为块级元素并设置clear:both; 实质上就等同于第二种方法添加空元素撑开父容器高度,但是这种方法很优雅,我们可以定义一个公共类名,并给这个类名添加清除浮动的样式,但凡是要清除浮动的元素,直接添加一个这样的公共类名上去

ul::after就是在ul的开标签之后添加伪元素,同理before就是闭标签之前添加伪元素;content指明伪元素里面的内容,伪元素样式中必须有这个属性

</style>
    /* 其他样式省略 */
    ul::after{
         content: ''; 
         display: block;
         clear: both;
    }
</style>
<body>
    <ul>
        <li class="item">1</li>
        <li class="item">2</li>
        <li class="item">3</li>
    </ul>    
    <div class="title">这是标题</div>
</body>

4. 把父容器设置成BFC容器

例如给父容器ul添加 overflow: hidden / auto;等, 文章后面讲讲BFC容器

5. 给后面被影响的元素设置clear:both;

有用但也非常不推荐,它会造成浮动元素li有高度但是父容器ul没有高度,让页面布局很乱

</style>
    /* 其他样式省略 */
    .title{
         clear: both;
     }
</style>
<body>
    <ul>
        <li class="item">1</li>
        <li class="item">2</li>
        <li class="item">3</li>
    </ul>    
    <div class="title">这是标题</div>
</body>

实际开发中,只有利用伪元素和将父容器设置成BFC容器比较常用,其他都不太推荐

BFC容器

css有一个天生存在的bug: 父容器和子容器会上下margin重叠。看例子:

<head>
    <title>BFC</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        .wrap{
            height: 500px;
            background-color: red;
            margin-top: 100px;
        }
        .box{
            height: 200px;
            background-color: aquamarine;
            margin-top: 50px;
        }
    </style>
</head>
<body>
    <div class="wrap">
        <div class="box"></div>
    </div>
</body>

我们给红色父容器wrap设置了 margin-top: 100px; 给蓝色子容器box设置了 margin-top: 50px; 我们希望红色父容器距离顶部有100px,蓝色子容器距离红色父容器顶部有50px,但效果却是子容器50px上外边距重叠了父容器的100px上外边距

屏幕截图 2024-08-10 171608.png

为了解决这种margin重叠问题,我们可以把父容器设置成BFC容器

概念

BFC(Block formatting context),块级格式化上下文,它是指一个独立的块级渲染区域,只有Block-level Box(块级元素)参与,该区域拥有一套渲染规则来约束块级盒子的布局,使它的子元素与外部隔绝

BFC 布局规则

  1. 内部的Box会在垂直方向,一个接一个地放置
  2. BFC容器内部和外部的容器相互隔离,互不影响 ———— 解决margin重叠问题
  3. BFC容器内部,在垂直方向上相邻元素的margin会重叠(普通容器也是如此)
  4. BFC容器在计算高度时,内部浮动元素也参与计算(即撑开父容器高度) ———— 清除浮动

(但注意:不是所有脱离文档流的元素都参与BFC父容器高度的计算,例如通过定位脱离文档流的元素就不会撑开BFC父容器的高度 )

把一个容器设置为BFC的方法

  1. 设置 overflow: hidden || auto || overlay || scroll
  2. 子元素都是浮动元素,那么就把父容器也设置 float: left || right 变成浮动元素。 但是不推荐!虽然解决了父容器高度塌陷的问题,但还是会影响后面元素的布局
  3. 设置绝对定位和固定定位position: absolute || fixed
  4. 设置 display: inline-block || inline-flex || inline-XXX
  5. 设置 display: table-cell || table-row || table-XXX
  6. 设置 display: flex || inline-flex