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

写在最前

习惯性去谷歌翻译看了看 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

如果您觉得本文不错,

请点击文章底部广告,支持一下我啦!

原创系列推荐

1. JavaScript 重温系列(22篇全)

2. ECMAScript 重温系列(10篇全)

3. JavaScript设计模式 重温系列(9篇全)

4. 正则 / 框架 / 算法等 重温系列(16篇全)

5. Webpack4 入门手册(共 18 章)(上)

6. Webpack4 入门手册(共 18 章)(下)

7. 59篇原创系列汇总

点这,与大家一起分享本文吧~

【CSS】323- 深度解析 CSS 中的“浮动”的更多相关文章

  1. 深度解析javascript中的浅复制和深复制

    原文:深度解析javascript中的浅复制和深复制 在谈javascript的浅复制和深复制之前,我们有必要在来讨论下js的数据类型.我们都知道有Number,Boolean,String,Null ...

  2. 深度解析VC中的消息(转发)

    http://blog.csdn.net/chenlycly/article/details/7586067 这篇转发的文章总结的比较好,但是没有告诉我为什么ON_MESSAGE的返回值必须是LRES ...

  3. 深度解析CSS中的单位以及区别

    css中有几个不同的单位表示长度,使用时数字加单位.如果长度为0,则可以省略单位. 长度单位可分为两种类型:相对和绝对. 绝对长度 绝对长度单位是一个固定的值,反应真实的物理尺寸,不依赖于显示器.分辨 ...

  4. CSS 继承深度解析

    FROM ME: 之前在研究前端性能优化的时候,就有学习关于CSS中“善用CSS中的继承”. 原文:CSS Inheritance, The Cascade And Global Scope: You ...

  5. 【转载】深度解析Android中字体设置

    原文:http://mobile.51cto.com/android-265238.htm 1.在Android XML文件中设置字体 可以采用Android:typeface,例如android:t ...

  6. 深度解析Java中的那把锁

    锁的本质 我们先来讨论锁的出现是为了解决什么问题,锁要保证的事情其实很好理解,同一件事(一个代码块)在同一时刻只能由一个人(线程)操作. 这里所说的锁为排他锁,暂不考虑读写锁的情况 我们在这里打个比方 ...

  7. 深度解析VC中的消息传递机制

    摘要:Windows编程和Dos编程,一个很大的区别就是,Windows编程是事件驱动,消息传递的.所以,要学好Windows编程,必须 对消息机制有一个清楚的认识,本文希望能够对消息的传递做一个全面 ...

  8. 深度解析Struts2中ValueStack

    1.什么是ValueStack 对于每一个action的调用,Struts在执行相应的动作方法之前会先创建一个名为ValueStack的对象.Value Stack用来保存该动作对象或者对象.由于最终 ...

  9. 深度解析VC中的消息

    消息是指什么? 消息系统对于一个win32程序来说十分重要,它是一个程序运行的动力源泉.一个消息,是系统定义的一个32位的值,他唯一的定义了一个事件,向Windows发出一个通知,告诉应用程序某个事情 ...

随机推荐

  1. 在linux (centos)上使用puppeteer实现网页截图

    1.安装nodejs和npm # 下载解压 wget -c https://nodejs.org/dist/v8.9.1/node-v8.9.1-linux-x64.tar.xz tar -xvf n ...

  2. 领扣(LeetCode)找树左下角的值 个人题解

    给定一个二叉树,在树的最后一行找到最左边的值. 示例 1: 输入: 2 / \ 1 3 输出: 1 示例 2: 输入: 1 / \ 2 3 / / \ 4 5 6 / 7 输出: 7 注意: 您可以假 ...

  3. ZeroC ICE的远程调用框架 ServantLocator与Locator

    ServantLocator定位的目标是Servant,而Locator定位的目标是“Ice Object”,即一个可定位的“Ice Object”代理.Servant是::Ice::Object的继 ...

  4. 访问formData的数据

    vant-ui 的 Uploader 上传图片时,用到formData let fd = new FormData(); fd.append('upImgs', file.file); postIma ...

  5. 看完这篇还不会用Git,那我就哭了!

    你使用过 Git 吗?也许你已经使用了一段时间,但它的许多奥秘仍然令人困惑. Git 是一个版本控制系统,是任何软件开发项目中的主要内容.通常有两个主要用途:代码备份和代码版本控制.你可以逐步处理代码 ...

  6. Golang 入门系列(十六)锁的使用场景主要涉及到哪些?读写锁为什么会比普通锁快

    前面已经讲过很多Golang系列知识,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html, 接下来要说的 ...

  7. Java数组定义及初始化

    数组定义及初始化 数组这玩意是一种用于存放数据最常见数据结构. 数组的的概念及注意点 数组要求所有的数组元素具有相同的数据类型,且只能存在一种数据类型,要多专一有多专一. 数据类型既可以是基本类型也可 ...

  8. (五)OpenStack---M版---双节点搭建---Nova安装和配置

    ↓↓↓↓↓↓↓↓视频已上线B站↓↓↓↓↓↓↓↓ >>>>>>传送门 1.创建nova 和 nova_api数据库 2.获得 admin 凭证来获取只有管理员能执行的 ...

  9. nginx离线部署脚本

    #! /bin/bashbasepath=$(cd `dirname $0`; pwd)nginx_path=/usr/localfile_name=nginxecho "--------- ...

  10. Lua和C交互的简易教程

    转载请标明出处:http://blog.csdn.net/shensky711/article/details/52458051 本文出自: [HansChen的博客] Lua栈 要理解Lua和C++ ...