使得元素脱离文档流有两种方式。第一种是通过定位,第二种方法就是使用浮动。
浮动(float),是一个我们即爱又恨的属性。爱,因为通过浮动,我们能很方便地布局;恨,因为浮动之后遗留下来太多的问题需要解决,特别是 IE6-7(以下无特殊说明均指 windows 平台的 IE 浏览器)。如果不详细了解浮动,可能会觉得它很神秘也很复杂,很多网站的效果好看,但是自己就是做不出来。
很多初学者都会有这样的疑问:浮动从何而来?为什么要设置浮动?我们为何要清除浮动?清除浮动的原理是什么?
现在我们就深入剖析float的奥秘,解开这些问题的答案。
一、什么是浮动?浮动最常见的问题是什么?
最简单的解释,浮动可以使得多个块级元素可以放置在同一行上。例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>z-index</title>
</head>
<body>
<div class="main left">
.main:我是主要内容
</div>
<div class="side left">
.side:我是侧边栏
</div>
</body>
</html>
.main {
height: 60px;
width: 50%;
background: #FFE3D7;
}
.left {
float: left;
}
div {
padding: 15px 20px;
font-size: 14px;
color: #333;
}
.side {
width: 20%;
background: lightblue;
}
这种浮动有什么用?其实很多网站的两栏或者三栏结构都是利用浮动来实现的。例如:
然而浮动初学者经常出现的问题是,浮动元素脱离的文档流,因此,它无法使得其他元素和其相对位置关系保持正常。也无法使得自己的父容器正确计算自己的大小。对于上面的例子,如果我们使得 main 元素和 side 元素有一个父容器 wrap,并且父容器还有一个兄弟节点 footer:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>z-index</title>
</head>
<body>
<div class="warp">
<div class="main left">
.main:我是主要内容
</div>
<div class="side left">
.side:我是侧边栏
</div>
</div>
<div class="footer">
我是一个footer
</div>
</body>
</html>
.main {
height: 60px;
width: 50%;
background: #FFE3D7;
}
.left {
float: left;
}
div {
padding: 15px 20px;
font-size: 14px;
color: #333;
}
.side {
width: 20%;
background: lightblue;
}
.warp {
border: 1px solid blue;
width: 300px;
margin: 30px auto 5px;
background: #F5F5F5;
}
.footer {
border: 1px solid #ccc;
background: #EEE;
width: 300px;
margin: 5px auto 30px;
}
可以看到两个最大的问题:
- wrap 元素的高度无法正确覆盖住 main 和 side 元素。
- 由于 wrap 元素高度计算的问题,footer 元素本身显示的位置非常奇怪。通常解决浮动元素带来的问题有两种主要方式:清除浮动和闭合浮动。那么:
二、该 清除浮动 还是 闭合浮动?
很多人都已经习惯称之为清除浮动,以前我也一直这么叫着,但是确切地来说是不准确的。我们应该用严谨的态度来对待代码,也能更好地帮助我们理解上面的问题。
1)清除浮动:清除对应的单词是 clear,对应 CSS 中的属性是 clear:left | right | both | none;
2)闭合浮动:更确切的含义是使浮动元素闭合,从而减少浮动带来的影响。
两者的区别:
两者的区别:
清除浮动:
<div class="warp">
<div class="main left">
.main:很抱歉,现代浏览器中我没能把warp撑高(float:left)
</div>
<div class="side left">
.side:我也浮动了(float:left)
</div>
</div>
<div class="footer clear">
.footer:我通过设置clear:both <strong>清除浮动</strong>,虽然位置正确了,但是wrap的高度没变,还是没达到想要的效果
</div>
.clear {
clear: both;
}
<div class="warp clearfix">
<div class="main left">
.main:warp自己闭合浮动了,所以footer不用再清除浮动了(float:left)
</div>
<div class="side left">
.side:我也浮动了(float:left)
</div>
</div>
<div class="footer clear">
.footer:warp通过 .clearfix 已经<strong>闭合浮动</strong>了
</div>
.clearfix:after {
clear: both;
content: ".";
display: block;
height: 0;
visibility: hidden;
}
.clearfix {
*zoom: 1;
}
通过以上实例发现,其实我们想要达到的效果更确切地说是闭合浮动,而不是单纯的清除浮动,在 footer 上设置 clear:both 清除浮动并不能解决 wrap 高度塌陷的问题。
结论:用闭合浮动比清除浮动更加严谨,所以后文中统一称之为:闭合浮动。
三、为何要闭合浮动?
要解答这个问题,我们得先说说 CSS 中的定位机制:普通流,浮动,绝对定位(其中"position:fixed" 是 “position:absolute” 的一个子类)。
1)普通流:很多人或者文章称之为文档流或者普通文档流,其实标准里根本就没有这个词。如果把文档流直译为英文就是 document flow,但标准里只有另一个词,叫做普通流(normal flow),或者称之为常规流。但似乎大家更习惯文档流的称呼,因为很多中文翻译的书就是这么来的。比如《CSS Mastery》,英文原书中至始至终都只有普通流 normal flow(普通流)这一词,从来没出现过 document flow(文档流)
2)浮动:浮动的框可以左右移动,直至它的外边缘遇到包含框或者另一个浮动框的边缘。浮动框不属于文档中的普通流,当一个元素浮动之后,不会影响到块级框的布局而只会影响内联框(通常是文本)的排列,文档中的普通流就会表现得和浮动框不存在一样,当浮动框高度超出包含框的时候,也就会出现包含框不会自动伸高来闭合浮动元素(“高度塌陷”现象)。顾名思义,就是漂浮于普通流之上,像浮云一样,但是只能左右浮动。
正是因为浮动的这种特性,导致本属于普通流中的元素浮动之后,包含框内部由于不存在其他普通流元素了,也就表现出高度为 0(高度塌陷)。在实际布局中,往往这并不是我们所希望的,所以需要闭合浮动元素,使其包含框表现出正常的高度。
四、该如何正确闭合浮动呢?
先看一下闭合浮动的各种方法:
1)添加额外标签
一种方法,通过在浮动元素末尾添加一个空的标签例如
,其他标签 br 等亦可。例如:<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>z-index</title>
</head>
<body>
<div class="warp">
<div class="main left">
.main:我是主要内容
</div>
<div class="side left">
.side:我是侧边栏
</div>
<div class="clear"></div>
</div>
<div class="footer">
我是一个footer
</div>
</body>
优点:通俗易懂,容易掌握
缺点:可以想象通过此方法,会添加多少无意义的空标签,有违结构与表现的分离的思想,在后期维护中将是噩梦,这是坚决不能忍受的,所以我们不推荐使用该方法。
2)使用 br 标签和其自身的 html 属性
这个方法有些小众,br 有 clear=“all | left | right | none” 属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>z-index</title>
</head>
<body>
<div class="warp">
<div class="main left">
.main:我是主要内容
</div>
<div class="side left">
.side:我是侧边栏
</div>
<br clear="all">
</div>
<div class="footer">
我是一个footer
</div>
</body>
</html>
优点:比空标签方式语义稍强,代码量较少
缺点:同样有违结构与表现的分离,不推荐使用
3)父元素设置 overflow:hidden
通过设置父元素 overflow 值设置为 hidden;在 IE6 中还需要触发 hasLayout,例如 zoom:1;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>z-index</title>
</head>
<body>
<div class="warp close">
<div class="main left">
.main:我是主要内容
</div>
<div class="side left">
.side:我是侧边栏
</div>
</div>
<div class="footer">
我是一个footer
</div>
</body>
</html>
.close {
overflow: hidden;
*zoom: 1;
}
优点:不存在结构和语义化问题,代码量极少
缺点:内容增多时候容易造成不会自动换行导致内容被隐藏掉,无法显示需要溢出的元素;所以也不推荐使用。
4)父元素设置 overflow:auto 属性
同样 IE6 需要触发 hasLayout,演示和 3 差不多
优点:不存在结构和语义化问题,代码量极少
缺点:多个嵌套后,Firefox 某些情况会造成内容全选;IE 中 mouseover 造成宽度改变时会出现最外层模块有滚动条等,Firefox 早期版本会无故产生 focus等。
5)父元素也设置浮动
优点:不存在结构和语义化问题,代码量极少
缺点:使得与父元素相邻的元素的布局会受到影响,不可能一直浮动到 body,不推荐使用。
6)父元素设置 display:table
.close {
display: table;
}
优点:结构语义化完全正确,代码量极少。
缺点:盒模型属性已经改变,由此造成的一系列问题,得不偿失,不推荐使用。
7)使用:after伪元素
需要注意的是:after 是伪元素(Pseudo-Element),不是伪类(某些 CSS 手册里面称之为“伪对象”),很多闭合浮动大全之类的文章都称之为伪类,不过要严谨一点,这是一种态度。
由于 IE6-7 不支持:after,使用 zoom:1 触发 hasLayout。
优点:结构和语义化完全正确,代码量中等
缺点:复用方式不当会造成代码量增加
小结:
通过对比,我们不难发现,其实以上列举的方法,无非有两类:
其一,通过在浮动元素的末尾添加一个空元素,设置 clear:both 属性,after 伪元素其实也是通过 content 在元素的后面生成了内容为一个点的块级元素;
其二,通过设置父元素 overflow 或者 display:table 属性来闭合浮动,我们来探讨一下这里面的原理。
作者:灯火葳蕤234
链接:https://www.jianshu.com/p/2c1708a73438
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。