多是最全面最易懂的解析前端浮动的文章

写在最前

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

image
其中有一句这样写的:

she relaxed, floating gently in the waterhtml

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

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

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

找出问题是关键

问本身三个问题:bash

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

第二,如何解决这些由于浮动而形成的影响?

第三,bfc原理?
复制代码

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

好比看下面这段代码:spa

<!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>
复制代码

效果图以下:翻译

image

看到这,是否是有些理解了。从上图会发现,即便图片浮动了,脱离了正常文档流,也覆盖在没有浮动的元素上了,可是其并无将文本内容也覆盖掉,这也证明了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>
复制代码

效果图以下:

image

咱们能够看到,设置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>
复制代码

效果图以下:

image

从图中的标注和说明咱们能够清晰的知道,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>
复制代码

效果图以下:

image
经过图中的标注咱们能够很清晰看到上面提到的三个影响,那么影响也清晰的看到了,下面该如何去解决这些影响呢?

解决思路很重要

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

第一个方向:解决父元素给其同级的元素形成的影响,我比喻成解决外部矛盾

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

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

解决外部矛盾

触发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>
复制代码

效果图以下:

image
图中能够很清晰的看出,触发父元素的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,先看总体效果图吧:

image
不出意外,从上图能够看到,外部矛盾被解决了。这只是开始,你们眼睛盯好,继续看下面截图:


image
从图中标注能够看出,为何伪元素要设置 display:block,继续看下一个截图。


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


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

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


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

image
发现清除浮动失败了,其实能够看出,给父元素增长一个伪元素来清除浮动的本质,是经过

给父元素再加一个块级子容器,固然这个也就是父元素的最后一个块级子容器了。同时给这个块级子容器设置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>
复制代码

效果图以下:

image

给内部元素设置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>
复制代码

效果图以下几张截图:

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

image

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

image

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

image

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

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

文末的可爱声明:若是转发或者引用,请贴上原连接,尊重一下熬夜完成的劳动成果😂。文章可能有一些错误,欢迎评论指出,也欢迎一块儿讨论。文章可能写的不够好,还请多多包涵。为了前端,我也是操碎了心,人生苦短,我学前端,多一点贡献,多一分开心~

相关文章
相关标签/搜索