了解奇怪的Float浮动

322 阅读6分钟

浮动

对于一个元素我们可以对其设置一个css属性float以开启浮动,常见的浮动方式有左浮动float:left;与右浮动float:right;

浮动规则

  1. 浮动元素排布规则是,向上向左或是向上向右排列
  2. 若空间无法容纳,则向下移动,空间足够后在向左、向右
  3. 浮动元素的顶边,不得高于上一个浮动元素的顶边。

例如有这样一段结构

<!DOCTYPE html>
<html lang="en">
<head>
    <title>demo</title>
    <style>
        .container{
            width: 300px;
            height: 300px;
            background-color: skyblue;
        }
        .container div{
            float: left;
        }
        .container div:last-child{
            float: right;
        }
        .box1{
            width: 200px;
            height: 50px;
            background-color: #f66;
        }
        .box2{
            width: 50px;
            height: 100px;
            background-color: #6f6;
        }
        .box3{
            width: 100px;
            height: 100px;
            background-color: #66f;
        }
        .box4{
            width: 100px;
            height: 50px;
            background-color: #6ff;
        }
        .box5{
            width: 50px;
            height: 150px;
            background-color: #ff6;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="box1">box1</div>
        <div class="box2">box2</div>
        <div class="box3">box3</div>
        <div class="box4">box4</div>
        <div class="box5">box5</div>
    </div>
</body>
</html>

我们用了五个div,并让前四个div左浮动,最后一个右浮动,最后产生的效果是:

image.png

我们可以看到的是box3因为box2右边的空间不足以容纳它,所以它移至下一行,但其又不能超过上一个浮动元素(box2)的高度,所以其在box2的底线下方,box4同理。box5也是因为不能超过上一个浮动元素(box4)的高度,所以明明box2右边可容纳,但却在box2下方。

关于文档流

将元素开启浮动后,其会与开启绝对定位或固定定位类型脱离文档流。 但其又与定位脱离文档流有着区别。例如: 我们将上例中的box只留下1,2,3三个,删除原来的浮动,并将其宽高设为一致,再将2设置左浮动,3设置绝对定位

.box1{
    width: 100px;
    height: 100px;
    background-color: #f66;
}
.box2{
    width: 100px;
    height: 100px;
    background-color: #6f6;
    float: left;
}
.box3{
    width: 100px;
    height: 100px;
    background-color: #66f;
    position: absolute;
}

得到的结果如下box2为浮动元素,box3为绝对定位元素,但box3却把box2覆盖了,说明浮动元素的层级没有定位元素的层级高。

image.png

或者我们将box2改为绝对定位,box3改为浮动,结果还是一样的,开启绝对定位的元素在浮动元素上方。

image.png

同时我们要注意的是开启浮动之后,display属性都会变成block,宽度和高度都是由内容撑开的,默认情况浮动元素和普通元素在同一个包含块。

包含块指的是:

  1. 元素没有脱离文档流,父元素就是他的包含块
  2. 元素脱离了文档流(如开启了绝对定位),第一个开启定位属性的祖先元素就是他的包含块

浮动产生的影响

高度坍塌

这是浮动最常见的影响,其产生的根本问题是父元素的高度是自适应,其子元素浮动了。 例如: 我们将containerheight设置为auto,并只将box3设置浮动

.container{
    width: 300px;
    height: auto;
    background-color: skyblue;
}
.box1{
    width: 100px;
    height: 100px;
    background-color: #f66;
}
.box2{
    width: 100px;
    height: 100px;
    background-color: #6f6;
}
.box3{
    width: 100px;
    height: 100px;
    background-color: #66f;
    float: left;
}

产生的效果如下,由于父元素的高度是由子元素撑开,若box3未开启浮动则其父元素高度应为300px,但由于box3浮动父元素不会计算box3的高度,导致原本box3的空间没有了。

image.png

影响其兄弟元素

若我们只将box2开启浮动,会得到下面的结果:

image.png

由于box2开启了浮动所以其原有的高度没有了,box3占据了box2原来的位置,可是奇怪的是,box3中的内容却被挤到了外面, 这主要是因为:

  • 普通元素在前(box1),浮动元素在后(box2),浮动元素排布的时候,会避开普通元素
  • 浮动元素在前(box2),普通元素在后(box3),普通元素排布的时候,无视浮动元素
  • 行元素(box3的内容)在排列的时候会避开浮动元素

避开的意思有点类似前面有东西阻挡了该元素,这可能就是浮动的设计初衷,我们就可以利用该特性做一些文字环绕的效果,类似:

image.png

同时我们可以设置想要环绕元素的shape-outside属性来改变环绕方式,例如我们做一个环形环绕:

.box1{
    width: 200px;
    height: 200px;
    background-color: #f66;
    float: left;
    border-radius: 50%;
    shape-outside: margin-box;
}

效果如下:

image.png

去除浮动产生的影响

  1. 设置height属性:浮动产生的主要影响是高度坍塌,它又是因为父元素高度自适应,若父元素高度不是自适应那自然就没有了,但其不能解决浮动对后面元素的影响。

  2. 将父元素设置为BFC:设置BFC的方式有很多但大多有副作用我们简单列举两个

    • 设置overflow:hidden:可以解决高度坍塌,但会导致溢出部分掩藏。
    • 设置float:将父元素设置为浮动可以解决子元素导致的高度坍塌,但也会因为自身又开始对其他元素产生影响;
  3. 为需要清除浮动影响的元素添加clear属性:常用的值有三个:left清除左浮动影响,right清除右浮动影响,both清除左右浮动影响。

    .container{
        width: 500px;
        height: auto;
        background-color: skyblue;
    }
    .box1{
        width: 100px;
        height: 100px;
        background-color: #f66;
    }
    .box2{
        width: 100px;
        height: 100px;
        background-color: #6f6;
        float: left;
    }
    .box3{
        width: 100px;
        height: 100px;
        background-color: #66f;
        clear: both;
    }
    

    例如该代码中的box3就不会受box2的浮动影响,它表现得是一个正常排布

    image.png

  4. 通过设置伪元素来清除浮动影响:若我们没有多余的元素来清除浮动带来的影响我们就可以利用伪元素来代替这个工作。

    .container{
        width: 500px;
        height: auto;
        background-color: skyblue;
    }
    .container>div{
        margin:10px;
        float:left;
    }
    .container::after{
        content: "";
        display: block; /* 必须使用块盒,因为块是独占一行的,且可设置宽高 */
        clear: both;
    }
    .box1{
        width: 100px;
        height: 100px;
        background-color: #f66;
    }
    .box2{
        width: 100px;
        height: 100px;
        background-color: #6f6;
        float: left;
    }
    .box3{
        width: 100px;
        height: 100px;
        background-color: #66f;
    }
    

image.png

元素正常浮动,浮动所产生的影响(这里指的是高度坍塌)也没了。

补充BFC

  1. 开启BFC的区域是一块独立的渲染区域;
  2. 隔绝了内部外部的联系,内部渲染不会影响外部,它规定了在该区域中常规流块盒的布局;
  3. 常规流块盒在水平方向上,必须撑满包含块;
  4. 常规流块盒在垂直方向上依次摆放;
  5. 常规流块盒若外边距无缝相连,则进行外边距合并 ;
  6. 常规流块盒的自动高度和摆放位置,无视浮动元素;
  7. 整个html就是一块BFC;
  8. 浮动与绝对定位元素可设置BFC;
  9. overflow不为visible的块盒为BFC;
  10. displaytable为BFC;

当然设置BFC的方式还有其他,我只列举了常见的几种。