清除浮动的四种⽅式及其原理理解
本⽂介绍了四种清除浮动的⽅法,并尝试解释其原理。在理解了各种清除浮动的原理之后,你会发现,很多清除浮动的⽅法本质上其实是⼀样的。掌握这些原理,相信你可以根据场景和需求,灵活运⽤原则发展出不同的清除浮动的⽅法,⽽不再死记或拘泥于⽂中提到的⽅法。
⼀、为什么要清除浮动
在讲清除浮动的⽅法之前,我们先来了解⼀下为什么要清除浮动,清除浮动的⽬的是什么,即,要解决什么样的问题。来看⼀个浮动的例⼦(略去了⽂字内容):
<div class="topDiv">
<div class="floatDiv">float left</div>
<div class="textDiv">...</div>
</div>
<div class="bottomDiv">...</div>
其样式为:
.topDiv {
width: 500px;
border: 2px solid black;
}
.floatDiv {
width: 100px;
height: 100px;
border: 2px dotted red;
color: red;
margin: 4px;
float: left;
}
.bottomDiv {
width: 500px;
height: 100px;
margin: 5px 0;
border: 2px dotted black;
}
.textDiv {
color: blue;
border: 2px solid blue;
}
在chrome中渲染的效果如下图所⽰:
浮动效果
这肯定不是我们想要的渲染效果,它可能存在如下问题:
1. ⽂字围绕浮动元素排版,但我们可能希望⽂字(.textDiv)排列在浮动元素下⽅,或者,我们并不希望.textDiv两边有浮动元素存在。
2. 浮动元素排版超出了其⽗级元素(.topDiv),⽗元素的⾼度出现了塌缩,若没有⽂字⾼度的⽀撑,不考虑边框,⽗级元素⾼度会塌缩成
零。
3. 浮动元素甚⾄影响到了其⽗元素的兄弟元素(.bottomDiv)排版。因为浮动元素脱离了⽂档流,.bottomDiv在计算元素位置的时候会忽略
其影响,紧接着上⼀个元素的位置继续排列。
解决第⼀个问题,需要清除.textDiv周围的浮动,⽽解决第⼆个问题,因为⽗元素的兄弟元素位置只受⽗元素位置的影响,就需要⼀种⽅法将⽗级元素的⾼度撑起来,将浮动元素包裹在其中,避免浮动元素影响⽗元素外部的元素排列。
接下来开始介绍清除浮动的⽅法。
⼆、清除浮动的⽅法
1. 利⽤clear样式
还是开篇的例⼦,我们给需要清除浮动的元素添加如下样式:
.textDiv {
color: blue;
border: 2px solid blue;
clear: left;
}
清除浮动后的渲染效果如下:
解释⼀下:
通过上⾯的样式,.textDiv告诉浏览器,我的左边不允许有浮动的元素存在,请清除掉我左边的浮动元素。然⽽,因为浮动元素(.floatDiv)位置已经确定,浏览器在计算.textDiv的位置时,为满⾜其需求,将.textDiv渲染在浮动元素下⽅,保证了.textDiv左边没有浮动元素。同时可以看出,⽗元素的⾼度也被撑起来了,其兄弟元素的渲染也不再受到浮动的影响,这是因为.textDiv仍然在⽂档流中,它必须在⽗元素的边界内,⽗元素只有增加其⾼度才能达到此⽬的,可以说是⼀个意外收获。(clear的值为both也有相同的效果,通俗理解就是,哪边不允许有浮动元素,clear就是对应⽅向的值,两边都不允许就是both)
但是,如果我们把HTML中的.floatDiv和.textDiv交换⼀下位置呢?
<div class="topDiv">
<div class="textDiv">...</div>
<div class="floatDiv">float left</div>
</div>
<div class="bottomDiv">...</div>
html里的float是什么意思 ⽆论.textDiv是否应⽤清除浮动,情况都是下⾯的样⼦:
.textDiv的位置先确定了,于是浮动元素就紧接着.textDiv下⽅渲染在⽗元素的左侧。然⽽,⽗元素的⾼度并没有被撑起来,没有将浮动影响“内化”,导致浮动影响到了接下来的元素排版。
看来,为达到撑起⽗元素⾼度的⽬的,使⽤clear清除浮动的⽅法还是有适⽤范围的。我们需要更加通⽤和可靠的⽅法。
(这⾥澄清⼀下,单从元素清除浮动的⾓度,clear完全已经达到了⽬的,它已经使得.textDiv特定的⽅向上不再有浮动元素,清除浮动其实仅仅针对需要清除浮动的元素本⾝⽽⾔,只关注⾃⾝需求是否达到,和外界没有什么关系,它不关注浮动是否超出⽗元素,以及浮动是否影响到后续元素排列。我们只是利⽤了浮动的⼀些特性达到某些⽬的,但这不是清除浮动关⼼的问题,只不过,相对于清除浮动,我们可能更加关⼼这些特性能为我们做些什么⽽已。我的理解是,清除浮动和撑起⽗元素⾼度其实是两个不同的问题,在这⾥,可以简单地理解为⼯具和⽬的之间的关系,接下来要讨论的两个⽅法都是在利⽤清除浮动这个⼯具在解决问题,它并不是清除浮动这个⼯具本⾝。不过,我们经常将两者混为⼀谈。sorry,有点啰嗦,看不懂就是我没表达清楚,跳过即可。。。)
2. ⽗元素结束标签之前插⼊清除浮动的块级元素
HTML结构如下,在有浮动的⽗级元素的末尾插⼊了⼀个没有内容的块级元素div:
<div class="topDiv">
<div class="textDiv">...</div>
<div class="floatDiv">float left</div>
<div class="blankDiv"></div>
</div>
<div class="bottomDiv">...</div>
应⽤样式:
.topDiv {
width: 500px;
border: 2px solid black;
}
.floatDiv {
width: 100px;
height: 100px;
border: 2px dotted red;
color: red;
margin: 4px;
float: left;
}
.bottomDiv {
width: 500px;
height: 100px;
margin: 5px 0;
border: 2px dotted black;
}
.textDiv {
color: blue;
border: 2px solid blue;
}
// 区别在这⾥
.blankDiv {
clear: both; // or left
}
渲染效果如下:
原理⽆需多讲,和第⼀个例⼦⾥.textDiv应⽤clear清除浮动,撑起⽗级元素⾼度的原理完全⼀样。这⾥强调⼀点,即,在⽗级元素末尾添加的元素必须是⼀个块级元素,否则⽆法撑起⽗级元素⾼度。
3. 利⽤伪元素(clearfix)
HTML结构如下,为了惯例相符,在.topDiv的div上再添加⼀个clearfix类:
<div class="topDiv clearfix">
<div class="textDiv">...</div>
<div class="floatDiv">float left</div>
</div>
<div class="bottomDiv">...</div>
样式应⽤如下:
// 省略基本的样式
// 区别在这⾥
.clearfix:after {
content: '.';
height: 0;
display: block;
clear: both;
}
该样式在clearfix,即⽗级元素的最后,添加了⼀个:after伪元素,通过清除伪元素的浮动,达到撑起⽗元素⾼度的⽬的。注意到该伪元素的display值为block,即,它是⼀个不可见的块级元素(有的地⽅使⽤table,因为table也是⼀个块级元素)。你可能已经意识到,这也只不过是前⼀种清除浮动⽅法(添加空⽩div)的另⼀种变形,其底层逻辑也是完全⼀样的。前⾯的三种⽅法,其本质上是⼀样的。
4. 利⽤overflow清除浮动
⾸先直观地看看,overflow是如何清除浮动的。
HTML结构如下:
<div class="topDiv">
<div class="floatDiv">float left</div>
<div class="textDiv">...</div>
</div>
<div class="bottomDiv">...</div>
样式应⽤如下:
.topDiv {
width: 500px;
padding: 4px;
border: 2px solid black;
// 区别在这⾥
overflow: auto;
}
.floatDiv {
width: 100px;
height: 100px;
border: 2px dotted red;
color: red;
margin: 4px;
float: left;
}
.bottomDiv {
width: 500px;
height: 100px;
margin: 5px 0;
border: 2px dotted black;
clear: both;
}
.textDiv {
color: blue;
border: 2px solid blue;
}
不应⽤上⾯标识出来的CSS时,渲染结果和本⽂开始的第⼀个图形效果相同,应⽤CSS后的渲染效果如下:
仅仅只在⽗级元素上添加了⼀个值为auto的overflow属性,⽗元素的⾼度⽴即被撑起,将浮动元素包裹在内。看起来,浮动被清除了,浮动不再会影响到后续元素的渲染(严格讲,这和清除浮动没有⼀点关系,因为不存在哪个元素的浮动被清除,不纠结这个问题)。其实,这⾥的overflow值,还可以是除了"visible"之外的任何有效值,它们都能达到撑起⽗元素⾼度,清除浮动的⽬的。不过,有的值可能会带来副作⽤,⽐如,scroll值会导致滚动条始终可见,hidden会使得超出边框部分不可见等。那它们是如何做到浮动清除的呢?
要讲清楚这个解决⽅案的原理,有⼀个概念始终是绕不过去,那就是,然⽽这⼜是⼀个⾮常抽象的概念,如果要清楚地把这个概念讲出来,恐怕需要⾮常⼤的篇幅,这⾥仅提及和理解该问题相关的内容。
这是从上摘下来的BFC定义:
A block formatting context is a part of a visual CSS rendering of a Web page. It is the region in which the layout of block boxes occurs and in which floats interact with each other.
翻译过来就是:块级格式化上下⽂是CSS可视化渲染的⼀部分。它是⼀块区域,规定了内部块盒的渲染⽅式,以及浮动相互之间的影响关系。
块格式化上下⽂(BFC)有下⾯⼏个特点:
1. BFC是就像⼀道屏障,隔离出了BFC内部和外部,内部和外部区域的渲染相互之间不影响。BFC有⾃⼰的⼀套内部⼦元素渲染的规
则,不影响外部渲染,也不受外部渲染影响。
2. BFC的区域不会和外部浮动盒⼦的外边距区域发⽣叠加。也就是说,外部任何浮动元素区域和BFC区域是泾渭分明的,不可能重叠。
3. BFC在计算⾼度的时候,内部浮动元素的⾼度也要计算在内。也就是说,即使BFC区域内只有⼀个浮动元素,BFC的⾼度也不会发⽣
塌缩,⾼度是⼤于等于浮动元素的⾼度的。
4. HTML结构中,当构建BFC区域的元素紧接着⼀个浮动盒⼦时,即,是该浮动盒⼦的兄弟节点,BFC区域会⾸先尝试在浮动盒⼦的旁
边渲染,但若宽度不够,就在浮动元素的下⽅渲染。
有了这⼏点,就可以尝试解释为什么overflow(值不为visible)可以清除浮动了。
当元素设置了overflow样式,且值不为visible时,该元素就建构了⼀个BFC(哪些情况下,元素可以建构出BFC,可以看查看CSS⽂档对)。在我们的例⼦中,.topDiv因设置了值为auto的overflow样式,所以该元素建构出⼀个BFC,按照第三个特点,BFC的⾼度是要包括浮动元素的,所以.topDiv的⾼度被撑起来,达到了清除浮动影响的⽬的。(⾄于为什么值为visible的overflow不能建构BFC,给了⼀个解释)
其实,这⾥overflow的作⽤就是为了构建⼀个BFC区域,让内部浮动的影响都得以“内化”。如果你看了,你会发现,构建⼀个BFC区域的⽅法有很多种,overflow只是其中的⼀种,那在这⾥,我们是否也可以利⽤其它的⽅式构建BFC,且同样能达到清除浮动的⽬的呢?
BFC定义中说,inline-block同样也能构建BFC,那我们就⽤该样式来试试:
.topDiv {
width: 500px;
padding: 4px;
border: 2px solid black;
// 区别在这⾥
display: inline-block;
}
// 其他样式相同,省略
渲染效果如下:
效果完全⼀样!只要我们理解了原理,就可以灵活演变出不同的清除浮动的⽅法,⽽不必死记某种⼿段。
当然,要说明的是,在实际项⽬中选择采⽤哪种⽅式构建BFC是要具体问题具体分析的,因为要考虑到选⽤的样式⾃⾝的作⽤和影响。这个例⼦中,选⽤inline-block和选⽤overflow效果完全⼀样,没有
看出有什么副作⽤,但不代表在其他项⽬中⼀样能⾏得通。甚⾄对overflow值的选择也要考虑其表现和影响。在各种构建BFC的⽅式中,overflow⽅式可能是外部影响更可控的⼀种,我猜想这也许就是为什么普遍采⽤overflow来清除浮动的原因吧。
到这⾥,我要分享的清除浮动的⽅法已经讲完了。其实,如果在不同的使⽤场景下,对这⼏个⽅法进⾏拆分组合(其实是对底层原理的拆分组合),还可以实现其他形式不同的清除浮动的⽅法,最重要的还是对底层原理的把握。知其然,亦知其所以然才是最有效的学习⽅式。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论