在css中有许多布局方式,如:浮动布局、定位布局、弹性布局、网格布局和表格布局。今天我们来聊css中的浮动布局。
1. 浮动存在的意义
为什么会有浮动这个概念呢?它是用来干什么的?我们先通过一个例子来认识一下浮动。
<body>
<div class="box">
<img width="100" height="100"
src="https://img1.baidu.com/it/u=3610006291,1844666164&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800" alt="">
<p>今年是中巴建交50周年,中巴关系已成为发展中大国团结合作、携手发展的典范
。“中国和巴西同为发展中大国和重要新兴市场国家,是志同道合的好朋友、携手前行的好伙伴。”
志合者,不以山海为远。在此次拉美之行中,习近平主席将应邀对巴西进行国事访问。
在元首外交引领下,中国将同巴西进一步巩固双方政治互信,加强两国发展战略对接,
深化双方在全球热点问题上的战略沟通和协调,携手开启中巴关系下一个“黄金50年”。</p>
</div>
</body>
我们在html里添加一个类名为box的盒子,里面放了一张图片,然后在图片的下面放了一个p标签,里面放了一段文字。我们来看一下效果。
图片在左上角,而文字在图片下面。因为p标签是块级标签嘛,它要占据一整行。
那我们想让图片和文字出现在同一行应该怎么办呢?让文字环绕图片,在网页中很常见的结构嘛。
浮动就能发挥这个作用。我们给img标签写个样式,让它浮动起来,用float来解决。
<style>
img {
float: left;
}
</style>
float: left就是让图片向左浮动。这是我们来看看效果。
这样文字就去到图片的右边了让图片浮动了起来。
这就是浮动存在的意义:让文字能环绕图片。在当年的互联网时代,网页布局都很简陋,多是新闻网页,当时的人们就是想让图片和文字能出现在同一行,既美观又节省空间。所以就发明了浮动。
那为什么浮动会出现这种效果呢?
我们换种场景,我们不往图片下面添加文字,我们添加一个类名为red的盒子,给它增加一些样式,然后照样让图片浮动起来。我们来看看效果。
<body>
<div class="box">
<img width="100" height="100"
src="https://img1.baidu.com/it/u=3610006291,1844666164&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800" alt="">
<p>
<div class="red"></div>
</p>
</div>
</body>
<style>
img {
float: left;
}
.red {
width: 200px;
height: 200px;
background-color: red;
}
</style>
我们发现图片是不是和盒子重叠了呀,和上面的图片和文字呈现的效果有所不同。图片并没有盖住文字。而这里图片却盖住了盒子。这是为什么呢?
我们得来引入一个文档流的概念。什么叫文档流呢?文档流是浏览器默认的一种布局方式。
1. 从上往下,从左往右的布局排列,遵从标签的特性
标签的特性:
1.块级元素会独占一行,从上向下顺序排列。
•常用元素:div、 hr、p、hl~ho、ul、 ol、 dl、 form、table
2.行内元素会按照顺序,从左到右顺宇排列,碰到列父元素边缘则自动换行。
•常用元素:span、a、i、 em等
2. 浮动会导致元素脱离文档流
3. 文字一定不会被浮动元素盖住
所以图片能盖住盒子,而不能盖住文字。因为添加了浮动,导致了这个元素脱离了文档流,它就不能独占一行了。
那我们一般怎么去使用浮动呢?举个例子,我们写一个ul里面3个li,然后给它们写点样式,各自加一个背景颜色。
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</body>
<style>
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
width: 200px;
height: 50px;
}
li:nth-child(1) {
background-color: red;
}
li:nth-child(2) {
background-color: yellow;
}
li:nth-child(3) {
background-color: green;
}
</style>
我们来看一下输出结果:
输出结果显示每一个li独占一行,因为它是块级元素。
那我们想让这三个li去到同一行怎么做?
你肯定脱口而出用浮动呀,我们就是在聊浮动。
我们先不用浮动,有没有其它的办法让它们去同一行?
因为li是块级元素,我们把它转变成行内块元素就行了。
<style>
li {
width: 200px;
height: 50px;
display: inline-block;
}
</style>
输出结果显示:
确实到一行去了,但我们发现,每个li之间有一点小空隙,这个空隙是怎么来的?其实就是因为我们在写li的时候换行导致的。在浏览器渲染的时候,它会把换行处理成一个空格,所以会有间隙。
那我们不想要这个间隙,怎么去除它呢?我们这样去除。
<style>
ul {
list-style: none;
margin: 0;
padding: 0;
font-size: 0;
}
li {
width: 200px;
height: 50px;
display: inline-block;
font-size: 16px;
}
</style>
因为换行被看出了一个字符,那么我们只要让ul中的字符大小设置成0就行了,而因为我们在li中要输出1、2、3,所以再在li上再设置字符大小为16px就行了。这样ul中的空白字符就会消失,而li中的字符正常显示。
这样就让间隙消失了。
2. 浮动的负面影响
我们不用上面那种方法。我们来使用浮动去完成上面的效果,这会导致一个负面效果。我们来看。
<style>
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
width: 200px;
height: 50px;
float:left;
}
</style>
我们给3个li都添加向左浮动,在看结果之前,我们思考一下,我们没设置浮动之前,3个li是上下排列的,我们给li设置了高度50px,没有给ul设置高度,所以ul会被li撑开,高度应为150px。此时我们给li添加了浮动,它们去到了同一行,这时父容器ul的高度会是多少呢?
我们在浏览器中检查一下。
我们发现ul的高度变为0了。因为此时li添加了浮动导致脱离了文档流,没办法去撑开父容器ul,所以ul的高度就为0。
我们说的负面影响就在这体现。
我们在ul后面再写一个box,给他添加一些样式。宽为500px,高为100px。
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<div class="box"></div>
</body>
<style>
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
width: 200px;
height: 50px;
float: left;
}
li:nth-child(1) {
background-color: red;
}
li:nth-child(2) {
background-color: yellow;
}
li:nth-child(3) {
background-color: green;
}
.box {
width: 500px;
height: 100px;
background-color: #f007d5;
}
</style>
我们来看一下输出结果。
我们发现新添加的这个盒子被盖住了。因为ul没高度了,所以这个盒子就从左上角开始排列。
这就是浮动会导致的负面影响:浮动元素的高度不计算在父容器的高度之内,这就会导致父容器的后续容器布局和该浮动元素重叠。
而在我们日常工作中,我们写了一个盒子,肯定不希望它被上面的盒子盖住,有什么办法能去除这种影响吗?
3. 清除浮动
想要去除这种负面影响,就得聊到清除浮动了。
第一种方法,既然你是因为没有高度导致后续容器重叠,我直接给你设个高度就行了。我们给父容器ul设置高度为50px。来看看效果。
<style>
ul {
list-style: none;
margin: 0;
padding: 0;
height:50px
}
li {
width: 200px;
height: 50px;
float: left;
}
li:nth-child(1) {
background-color: red;
}
li:nth-child(2) {
background-color: yellow;
}
li:nth-child(3) {
background-color: green;
}
.box {
width: 500px;
height: 100px;
background-color: #f007d5;
}
</style>
确实得到了我们想要的样子,没有重叠。但这种方法我们一般不使用,因为在实际开发中,我们就是想让子容器撑开父盒子,不会给父容器增加高度,因为有时候子容器是一直向下延伸的,所以一般我们无法得知父容器的高度。
第二种方法,我们在在浮动元素最末尾增加一个子容器,在子容器上做清除浮动。例如:
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<div class="clear"></div>
</ul>
<div class="box"></div>
</body>
<style>
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
width: 200px;
height: 50px;
float: left;
}
li:nth-child(1) {
background-color: red;
}
li:nth-child(2) {
background-color: yellow;
}
li:nth-child(3) {
background-color: green;
}
.box {
width: 500px;
height: 100px;
background-color: #f007d5;
}
.clear {
clear: both
}
</style>
我们在ul的末尾加一个叫clear的盒子,给它写一个样式,clear: both、clear: left、clear: right,都行,清除浮动,将浮动的效果终止在这个盒子上,就不会影响到父盒子了。这样也能达到我们想要的效果。
但这种方法我们也一般不使用,因为每多一处我们都得添加一个清除浮动的盒子,浪费代码空间。
第三种方法,添加伪元素。我们在ul上添加伪元素,然后在伪元素上清除浮动。伪元素有两种,before和after,用哪种能清除浮动呢?我们来试一下。
<style>
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
width: 200px;
height: 50px;
float: left;
}
li:nth-child(1) {
background-color: red;
}
li:nth-child(2) {
background-color: yellow;
}
li:nth-child(3) {
background-color: green;
}
.box {
width: 500px;
height: 100px;
background-color: #f007d5;
}
ul::before {
content: "";
clear: both;
display: block;
}
</style>
我们在ul上添加了伪元素,把它转换成块级元素,然后清除浮动。注意,伪元素里一定要有‘content’属性。我们来看看效果。
好像并没有效果,box盒子还是被盖住了。这是因为before伪元素一定会出现在ul元素的最前面,所以也会在li前面,而我们是在li上添加的浮动,所以自然没有效果。
我们再来试一下after伪元素。
<style>
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
width: 200px;
height: 50px;
float: left;
}
li:nth-child(1) {
background-color: red;
}
li:nth-child(2) {
background-color: yellow;
}
li:nth-child(3) {
background-color: green;
}
.box {
width: 500px;
height: 100px;
background-color: #f007d5;
}
ul::after {
content: "";
clear: both;
display: block;
}
</style>
我们来看一下效果。
我们发现after伪元素成功清除了浮动。
伪元素清除法就是我们常用的方法。
还有第四种方法其实我们也不推荐使用。我们一起来看一下。
第四种方法就是给受影响的容器添加清除浮动。什么意思呢?我们添加的box盒子不是被盖住了嘛,那我们给这个受影响的box盒子添加浮动也能达到这个效果。
<style>
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
width: 200px;
height: 50px;
float: left;
}
li:nth-child(1) {
background-color: red;
}
li:nth-child(2) {
background-color: yellow;
}
li:nth-child(3) {
background-color: green;
}
.box {
width: 500px;
height: 100px;
background-color: #f007d5;
clear: both;
}
</style>
我们给box盒子添加了clear: both,我们来看看效果。
也成功去除了浮动。所以总结,清除浮动的方法一共有四种:
1. 直接设置父容器的高度
2. 在浮动元素最末尾增加一个子容器,在子容器上做清除浮动
3. 添加伪元素(最常用)
4. 给后面被影响的元素添加清除浮动
4. BFC容器 ---Block Formatting Contezt
其实我们还有一种最推荐的方法,就是BFC容器。我们看看它是怎么处理的。
BFC容器是什么呢?它是一个拥有隔离空间的容器
任何标签都能称为BFC容器,就是拥有块级格式上下文的容器。
它被创造出来是干什么的呢?
我们通过一个例子来认识一下它。
在html中有一个经典的的bug。
<body>
<div class="parent">
<div class="child"></div>
</div>
</body>
<style>
* {
margin: 0;
padding: 0;
}
.parent {
width: 100vw;
height: 400px;
background-color: purple;
}
.child {
width: 100vw;
height: 200px;
background-color: blue;
margin-top: 50px;
}
</style>
我们添加了一个父盒子,里面又添加了一个子盒子,给他们添加颜色、高度。然后我们给子容器添加一个外边距20px。 按理来说。子盒子添加了外边距20px是不是就应该离父盒子的上方有20px的距离。我们来看一下效果:
我们发现子盒子并没有离父盒子的上方有20px外边距,而是紧紧贴着父盒子的上方,并且把整个body拉下来了20px。这就是这个bug,而我们并不想要这个效果,该怎么去解决它呢?
这就是BFC容器存在的意义了,它一开始被设计出来就是为了解决父子容器margin重叠的问题
那把谁设计成BFC容器呢?我们给父盒子添加一个样式:overflow: auto;
<style>
* {
margin: 0;
padding: 0;
}
.parent {
width: 100vw;
height: 400px;
background-color: purple;
overflow: auto;
}
.child {
width: 100vw;
height: 200px;
background-color: blue;
margin-top: 50px;
}
</style>
我们把父容器改造成了BFC容器,我们来看看效果:
我们成功达到了我们想要的效果,父盒子里面的子盒子离父盒子上边距有20px,并且body也没有被拉下来20px。
除了上面那种方法,还有哪些方法能把容器设置成BFC容器呢?有下面几种:
创建BFC 的方法
- overflow:hidden || auto || overlay || scroll
- 定位: position: absolute || fixed
- display: inline-xxxx || flex || grid
- display: table || table-xxx
- 浮动:float: left || right
大家可以自行去试一下。只要把父容器设置为BFC容器,它就能变成一个拥有独立空间的容器,它里面的子元素就不会受影响,就能解决这个bug。
5. BFC容器可以用来清除浮动
那聊了这么多关于BFC容器的概念,它对于解决清除浮动有什么妙用呢?
我们回到我们ul里有3个li的例子,我们把ul设置为BFC容器看看。
<style>
ul {
list-style: none;
margin: 0;
padding: 0;
overflow: hidden;
}
li {
width: 200px;
height: 50px;
float: left;
}
li:nth-child(1) {
background-color: red;
}
li:nth-child(2) {
background-color: yellow;
}
li:nth-child(3) {
background-color: green;
}
.box {
width: 500px;
height: 100px;
background-color: #f007d5;
clear: both;
}
</style>
我们给父容器ul添加了一行属性:overflow: hidden;,这行代码可以把容器设置为BFC容器。现在我们来看看效果。
同样使box盒子没有和ul重叠,说明我们成功去除了浮动。
所以,只要把父盒子设置成BFC容器,它里面的子盒子添加浮动就不会有负面影响了。
所以BFC的特性:
- BFC容器是让处于BFC内部的元素与外部的元素相互隔离。使外部元素的定位不会相互影响。
- 解决外边距重叠问题
- BFC容器在计算高度时,会将浮动元素的高度也计算在内(解决浮动的负面影响)