【CSS】323- 深度解析 CSS 中的“浮动”

对于浮动这篇文章解析的狠透彻 ~

写在最前

习惯性去谷歌翻译看了看 float 的解释:

其中有一句这样写的:

she relaxed, floating gently in the water

瞬间浮想联翩,一个女神,轻轻地漂浮在水中。开心的拍打着水花,哇靠。。。

不想了,人间不值得,步入正题吧,上面美妙的画面中,我们可以看到,女神还是挤占了水的空间,女神是浮动的。那么来,好了,编不下去了,直接开题吧。。。

我觉得很多人连float是啥意识都不知道,要知道很多特性的原理是和其命名的单词或者字母有密切关联的,不是随便命名的。从名字中可以看到一些当初设计的初衷。

找出问题是关键

问自己三个问题:

第一 浮动会造成什么影响?

第二,如何解决这些因为浮动而造成的影响?

第三,bfc原理?
复制代码

其实我个人理解,浮动造成的最核心的问题就是破坏了文档流,那么问题来了,float破坏了文档流,为什么还要设计这个api,我查了一些资料最后才知道,这是因为当初设计float的目的是为了能实现文字能够环绕图片的排版功能,也就是我们有时会纳闷的一点:设置浮动后,还是会挤占容器中的文本内容。

比如看下面这段代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>float实现浮动</title>
</head>
<style>
    .z1{
        height: 200px;
        width: 200px;
        float: left;
        text-align: center;
        line-height: 200px;
        background: skyblue;
    }
    .fu {
        width: 400px;
    }
</style>
<body>
<div class="fu clearfix">
    <div class="z1">设置了float为left的图片</div>
    <div class="z2">你看,我没有被浮动哥哥挡住哦,这是一段神奇旅行,一天我遇上了白雪公主</div>
</div>
</body>
</html>
复制代码

效果图如下:

看到这,是不是有些理解了。从上图会发现,即使图片浮动了,脱离了正常文档流,也覆盖在没有浮动的元素上了,但是其并没有将文本内容也覆盖掉,这也证实了float这个api当初被设计出来的主要目的:实现文字环绕图片排版功能。

当想到这时,我突然意识到,其他布局模式是什么样子,然后进行了实验。去掉容器z1float属性,增加了position属性,代码如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>absolute实现浮动</title>
</head>
<style>
    .z1{
        height: 200px;
        width: 200px;
        box-sizing: border-box;
        position: absolute;
        text-align: center;
        background: skyblue;
        padding-top: 80px;
        opacity: 0.8;
    }
    .fu {
        width: 400px;
    }
</style>
<body>
<div class="fu clearfix">
    <div class="z1">设置了positon为absolute的图片</div>
    <div class="z2">你看,我被absolute哥哥挡住哦,这是一段神奇旅行,一天我遇上了白雪公主</div>
</div>
</body>
</html>
复制代码

效果图如下:

我们可以看到,设置absolute的容器,才是意义上的完全脱离正常文档流。覆盖在当前位置上的所有容器和文本内容之上。对比思考一下,会发现这又证明了float被设计出来的主要目的。如果能理解成这样,我觉得对于不同业务上该用什么方式清除float,或者说该用什么来代替float,将会有个很明确的方向。

其实你会发现,absolutefloat都不会去覆盖掉在他们之前的正常文档流,这应该和浏览器渲染机制有关系,会从上到下依次渲染内容,渲染成功后,就不会因为后续元素浮动而使其被覆盖住 (不考虑使用 fix 等强行覆盖的情况)。

简易代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>清除float浮动</title>
</head>
<style>
    .z1{
        height: 200px;
        width: 200px;
        box-sizing: border-box;
        float: left;
        text-align: center;
        background: skyblue;
        padding-top: 80px;
        opacity: 0.5;
    }
    .z2 {
        background: yellow
    }
    .z3 {
        background: red;
    }
    .z4 {
        background: green;
    }
    .z5 {
        background: pink;
    }
</style>
<body>
<div class="fu">
    <div class="z2">没有设置任何浮动的容器,背景为黄色</div>
    <div class="z3">没有设置任何浮动的容器,背景为红色</div>
    <div class="z1">设置了浮动的元素,opacity为0.5</div>
    <div class="z4">没有设置任何浮动的容器,背景为绿色</div>
    <div class="z5">没有设置任何浮动的容器,背景为粉色</div>
</div>
</body>
</html>
复制代码

效果图如下:

从图中的标注和说明我们可以清晰的知道,float不会影响前面已经渲染好的文档,而会影响在其后面将要渲染的文档。那么问题来了,怎样才能消除因为z1的浮动而对z4,z5造成的影响呢?

首先我们要知道,z1这个浮动造成了哪些影响,影响如下:

第一个影响:影响了z4,z5的布局。 第二个影响:影响了父容器的高度,正常父元素的高度是自适应的,高度为其包含的内容总高度,而内部元素的浮动造成了父容器高度塌陷。 第三个影响:父容器高度塌陷了,将会影响和父元素同级的文档布局。

下面的代码可以完美的诠释这些影响:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>清除float浮动</title>
</head>
<style>
    .z1{
        height: 200px;
        width: 200px;
        box-sizing: border-box;
        float: left;
        text-align: center;
        background: skyblue;
        padding-top: 80px;
        opacity: 0.5;
    }
    .z2 {
        background: yellow
    }
    .z3 {
        background: red;
    }
    .z4 {
        background: green;

    }
    .z5 {
        background: pink;
    }
    .z6 {
        color: #fff;
        background: black;
    }
    .z7 {
        color: #fff;
        background: blue;
    }
    .fu {
        /* overflow: hidden; */
    }
</style>
<body>
<div class="fu">
    <div class="z2">没有设置任何浮动的容器, 背景为黄色</div>
    <div class="z3">没有设置任何浮动的容器, 背景为红色</div>
    <div class="z1">设置了浮动的元素, opacity为0.5</div>
    <div class="z4">没有设置任何浮动的容器, 背景为绿色</div>
    <div class="z5">没有设置任何浮动的容器, 背景为粉色</div>
</div>
<div class="z6">和父级元素同级的容器, 没有设置任何浮动, 背景为绿色</div>
<div class="z7">和父级元素同级的容器, 没有设置任何浮动, 背景为绿色</div>
</body>
</html>
复制代码

效果图如下:

通过图中的标注我们可以很清晰看到上面提到的三个影响,那么影响也清晰的看到了,下面该如何去解决这些影响呢?

解决思路很重要

要解决这三个影响,需要从两个方向思考:

第一个方向:解决父元素给其同级的元素造成的影响,我比喻成解决外部矛盾。 第二个方向:解决父级元素内部的浮动元素对其同级元素的影响,我比喻成解决内部矛盾。

俗话说的好,家丑不可外扬,那么来,现在就先解决外部矛盾,怎么解决呢,解决的思想,无非就是让父级元素的高度不再塌陷,把浮动元素的高度算进去。记住一个关键点,这时候,内部矛盾还是存在的。比如浮动元素和其后续的同级元素有高度重叠。

解决外部矛盾

触发 bfc

第一个是触发bfc,为什么呢,因为触发bfc后,高度会包括浮动元素的高度。怎么触发呢,可以给父级元素设置overflow:auto;对于其他的触发bfc方式,我就不说了,我主要说一下原理。代码如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>清除float浮动</title>
</head>
<style>
    .z1{
        height: 200px;
        width: 200px;
        box-sizing: border-box;
        float: left;
        text-align: center;
        background: skyblue;
        padding-top: 80px;
        opacity: 0.5;
    }
    .z2 {
        background: yellow
    }
    .z3 {
        background: red;
    }
    .z4 {
        background: green;

    }
    .z5 {
        background: pink;
    }
    .z6 {
        color: #fff;
        background: black;
    }
    .z7 {
        color: #fff;
        background: blue;
    }
    .fu {
        overflow: hidden;
    }
</style>
<body>
<div class="fu">
    <div class="z2">没有设置任何浮动的容器, 背景为黄色</div>
    <div class="z3">没有设置任何浮动的容器, 背景为红色</div>
    <div class="z1">设置了浮动的元素, opacity为0.5</div>
    <div class="z4">没有设置任何浮动的容器, 背景为绿色</div>
    <div class="z5">没有设置任何浮动的容器, 背景为粉色</div>
</div>
<div class="z6">和父级元素同级的容器, 没有设置任何浮动, 背景为绿色</div>
<div class="z7">和父级元素同级的容器, 没有设置任何浮动, 背景为绿色</div>
</body>
</html>
复制代码

效果图如下:

图中可以很清晰的看出,触发父元素的 bfc 后,外部矛盾解决了,但是内部的矛盾还没有解决。那么现在就开始解决内部矛盾。怎么解决内部矛盾呢,也就是父元素内部的浮动元素的高度和后面的同级元素的高度有重叠呢。这个时候,我们先不着急解决内部矛盾,我们来看一下,另一种解决外部矛盾的方式。

clear 原理

给父元素增加伪元素:代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>清除float浮动</title>
</head>
<style>
    .z1{
        height: 200px;
        width: 200px;
        box-sizing: border-box;
        float: left;
        text-align: center;
        background: skyblue;
        padding-top: 80px;
        opacity: 0.5;
    }
    .z2 {
        background: yellow
    }
    .z3 {
        background: red;
    }
    .z4 {
        background: green;
        /* clear: left */
    }
    .z5 {
        background: pink;
    }
    .z6 {
        color: #fff;
        background: black;
    }
    .z7 {
        color: #fff;
        background: blue;
    }
    .fu {
    }
    .clearfix:after {
        display: block;
        overflow: hidden;
        content: '伪元素的内容哦';
        clear: both;
        height: 0;
        background: slateblue;
    }
</style>
<body>
<div class="fu clearfix">
    <div class="z2">没有设置任何浮动的容器, 背景为黄色</div>
    <div class="z3">没有设置任何浮动的容器, 背景为红色</div>
    <div class="z1">设置了浮动的元素, opacity为0.5</div>
    <div class="z4">没有设置任何浮动的容器, 背景为绿色</div>
    <div class="z5">没有设置任何浮动的容器, 背景为粉色</div>
</div>
<div class="z6">和父级元素同级的容器, 没有设置任何浮动, 背景为绿色</div>
<div class="z7">和父级元素同级的容器, 没有设置任何浮动, 背景为绿色</div>
</body>
</html>
复制代码

很多人不清楚用伪元素清除浮动的原理是什么,为什么给父元素加这个伪元素,可以清除父元素的浮动。这里我故意在伪元素的content写了一些文本内容,同时加了背景色,有点像基佬色。。。


OK,先看整体效果图吧:

不出意外,从上图可以看到,外部矛盾被解决了。这只是开始,大家眼睛盯好,继续看下面截图:


从图中标注可以看出,为什么伪元素要设置display:block,继续看下一个截图。


从上图中可以知道,为什么height要设置成 0 了。如果content不是空字符串,那么就会在页面中显示内容。但其实清除浮动时,content都会写成空的字符串,如果content里面只设置成''空的字符,那么height也可以不写,包括overflow也可以不写,写heightoverflow都是为了代码的鲁棒性。不过有个很重要,content这个属性,必须要写,不写content,是没法清除浮动的。


最重要的知识点要来了,请看两个截图:

我故意让content显示出来,会发现伪元素清除浮动的核心原理其实是在给父元素增加块级容器,同时对块级容器设置clear属性,使其能够清除自身的浮动,从而正常按照块级容器排列方式那样排列在浮动元素的下面。同时,父元素的同级元素也会正常排列在伪元素形成的块级元素后面,而不受浮动影响。


下面是干掉clear属性后的截图:

发现清除浮动失败了,其实可以看出,给父元素增加一个伪元素来清除浮动的本质,是通过给父元素再加一个块级子容器,当然这个也就是父元素的最后一个块级子容器了。同时给这个块级子容器设置 clear 属性来清除其浮动,这样这个子容器就能排列在浮动元素的后面,同时也把父元素的高度撑起来了。那么父元素的同级元素也能正常排列了。所以这个子容器不能有高度和内容,不然会影响父元素的布局。

写到这,外部矛盾的解决方式和各自的原理已经说的很清楚了。那么内部矛盾怎么解决呢?

其实,解决内部矛盾的原理和解决外部矛盾的第二种方式的原理是一样的,通过给被浮动影响的第一个元素进行清除浮动,就可以使后面的元素也不会受到浮动影响了。代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>清除float浮动</title>
</head>
<style>
    .z1{
        height: 200px;
        width: 200px;
        box-sizing: border-box;
        float: left;
        text-align: center;
        background: skyblue;
        padding-top: 80px;
        opacity: 0.5;
    }
    .z2 {
        background: yellow
    }
    .z3 {
        background: red;
    }
    .z4 {
        background: green;
        clear:both;
    }
    .z5 {
        background: pink;
    }
    .z6 {
        color: #fff;
        background: black;
    }
    .z7 {
        color: #fff;
        background: blue;
    }
</style>
<body>
<div class="fu">
    <div class="z2">没有设置任何浮动的容器, 背景为黄色</div>
    <div class="z3">没有设置任何浮动的容器, 背景为红色</div>
    <div class="z1">设置了浮动的元素, opacity为0.5</div>
    <div class="z4">没有设置任何浮动的容器, 背景为绿色</div>
    <div class="z5">没有设置任何浮动的容器, 背景为粉色</div>
</div>
<div class="z6">和父级元素同级的容器, 没有设置任何浮动, 背景为绿色</div>
<div class="z7">和父级元素同级的容器, 没有设置任何浮动, 背景为绿色</div>
</body>
</html>
复制代码

效果图如下:

给内部元素设置clear:both;清除浮动后,会直接解决内部矛盾和外部矛盾。可能会有人想,如果 z4 容器后面又有一个浮动元素呢,这里我不想再解释了,因为可递归得出原理都是一样的,但是吧,我还是上个代码分析一下吧:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>清除float浮动</title>
</head>
<style>
    .z1{
        height: 200px;
        width: 200px;
        box-sizing: border-box;
        float: left;
        text-align: center;
        background: skyblue;
        padding-top: 80px;
        opacity: 0.5;
    }
    .z2 {
        background: yellow
    }
    .z3 {
        background: red;
    }
    .z4 {
        background: green;
        clear:both;
    }
    .z5 {
        background: pink;
        /* clear:both */
    }
    .z6 {
        color: #fff;
        background: black;
    }
    .z7 {
        color: #fff;
        background: blue;
    }
    .fu {
        overflow: auto;
    }
</style>
<body>
<div class="fu">
    <div class="z2">没有设置任何浮动的容器, 背景为黄色</div>
    <div class="z3">没有设置任何浮动的容器, 背景为红色</div>
    <div class="z1">设置了浮动的元素, opacity为0.5</div>
    <div class="z4">没有设置任何浮动的容器, 背景为绿色</div>
    <div class="z1">设置了浮动的元素, opacity为0.5</div>
    <div class="z5">没有设置任何浮动的容器, 背景为粉色</div>
</div>
<div class="z6">和父级元素同级的容器, 没有设置任何浮动, 背景为绿色</div>
<div class="z7">和父级元素同级的容器, 没有设置任何浮动, 背景为绿色</div>
</body>
</html>
复制代码

效果图如下几张截图:

父元素没有清除浮动,外部矛盾,内部矛盾都存在

父元素使用 bfc 清除浮动,外部矛盾解决,内部矛盾还存在

通过给父元素中的浮动元素后面的第一个同级块级元素设置 clear 清除浮动,内部矛盾解决,外部矛盾也解决。

对于clear还有leftright,这个就不说了,api的事情,正常both就可以了。写到此,差不多要结束了。最后再总结一下吧:

不同业务中可能需要不同的清除浮动的方式,不论选择哪一种方式,都避不开外部矛盾和内部矛盾,你的业务需要保留内部矛盾,只解决外部矛盾,还是外部矛盾和内部矛盾都解决。这些得需要根据业务的特点来决定。其次,是使用 bfc 还是 clear 还是伪元素,使用 bfc 的话使用哪种方式去触发。这也是根据业务的特点来决定。

本文作者:flyfee 原文地址:https://juejin.im/post/5bbe1054f265da0af2138c5e

本文分享自微信公众号 - 前端自习课(FE-study)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-08-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏web前端教室

实现网易考拉-首页-【7】-设置nodeJs静态目录

第二步,我们添加JavaScript让它再动起来,动起来之后再添加各种json数据;

9410
来自专栏我的前端路

最新15个加速 Web 开发的框架和工具

我们为开发人员挑选了15个最新的  Web 开发框架,你肯定尝试一下这些新鲜的框架,有的可能略微复杂,有的提供了很多的配置选项,也有一些窗口小部件和界面交互的选...

11900
来自专栏HACK学习

组合拳玩转self-xss

昨天跟朋友去看电影,团队的小伙伴说有个站点有个self-xss,想让我看看有没有什么好的利用方法,于是便有了此文章。

8420
来自专栏HACK学习

XSS绕过姿势

XSS为跨站攻击脚本,指攻击者将js脚本(可能是其他脚本)插入到web页面,当用户浏览该网页是,代码就会执行,造成恶意攻击。

22920
来自专栏前端入门学习

你不知道的web前端那些事

你不知道的web前端那些事,web前端要学习的知识有很多,前端基础要学习三个部分:HTML,CSS,JavaScript(简称JS),因此首先明确三个概念:HT...

7620
来自专栏grain先森

前端技能自检

前端开发是一个非常特殊的行业,它的历史实际上不是很长,但是知识之繁杂,技术迭代速度之快,是其他技术所不能比拟的。

26620
来自专栏萌兔it

前端面试宝典(二)

Hello小伙伴们,上次的题目做的如何呀~是不是觉得对知识点有了更深层次的理解了呢?我们今天还是6道题目哦!

6330
来自专栏数据分析1480

17398条B站评论,分析她为何受到技术宅的追捧?

7月番《工作细胞》最终话在十一前放出。这部动漫在b站上评分高达9.7。除了口碑之外,热度也居高不下,更值得关注的是连很多平时不关注动漫的小伙伴也加入了追番大军。...

7420
来自专栏web前端教室

大公司里怎样开发和部署前端代码?

然后,但凡是上规模的项目,都是动态发布的。一部分一部分的分块、栏目的进行灰度渐进的发布,然后上线之后还有各种意外的发生要进行调试,这就需要各种非覆盖发布的方式。...

11510
来自专栏海仔技术驿站

BootStrap框架总结

Bootstrap是最受欢迎的HTML,CSS和JS框架,用于开发响应式布局,移动设备优先的WEB项目.

12720

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励