Appearance
CSS3教程 - 7 浮动
我们之前学的布局都是垂直方向的布局,现在开始学习水平方向的布局——浮动。
7.1 浮动的使用
通过浮动可以使一个元素向其父元素的左侧或右侧移动。
使用 float 属性来设置于元素的浮动:
float: left;:将元素浮动到父元素的左侧;float: right;:将元素浮动到父元素的右侧;float: none;:取消浮动,默认值。
举个栗子:
html
<style>
.box1 {
width: 100px;
height: 100px;
background-color: red;
}
.box2 {
width: 120px;
height: 120px;
background-color: blue;
}
</style>
<body>
<div class="box1"></div>
<div class="box2"></div>
</body>上面是 box1 和 box2 都不浮动,效果如下:

都不浮动的情况下,一个元素在其父元素中,水平布局必须要满足以下的等式:
margin-left + border-left + padding-left + width + padding-right + border-right + margin-right = 其父元素的宽度
虽然 box1 右侧有很大的空间,但是根据上面的公式,右侧实际上都是 box1的 margin-right,所以 box2 只能在下面。
下面设置让 box1左浮动
css
.box1 {
width: 100px;
height: 100px;
background-color: red;
float: left;
}显示如下:

我们会发现,box1 左浮动后,它的位置没有变,但是 box2 向上移动到了 box1 下面。这是为什么呢?
这是因为 box1 设置左浮动后,box1 会向父元素的左侧移动,所以它移动到了父元素的最左侧。同时一个元素设置了浮动以后,它就脱离了文档流,不再占据文档流中的位置,所以 box2 会向上移动。
下面设置让 box1 右浮动
css
.box1 {
width: 100px;
height: 100px;
background-color: red;
float: right;
}显示如下:

box1 移动到了父元素的最右侧,box1 脱离了文档流后, box2 会向上移动。
通过上面可以发现:
- 元素设置浮动以后,水平布局的等式便不需要强制成立;
- 设置浮动以后,元素会向父元素的左侧或右侧移动;
- 元素设置浮动以后,会完全从文档流中脱离,不再占用文档流的位置,所以元素下边的还在文档流中的元素会自动向上移动;
- 浮动元素默认不会从父元素中移出,不进行特殊设置,不会超出父元素的左、右边界。
所以如果要实现水平方向的布局,只需要让元素都浮动起来排列:
html
<style>
.box1 {
width: 100px;
height: 100px;
background-color: red;
float: left;
}
.box2 {
width: 100px;
height: 100px;
background-color: blue;
float: left;
}
.box3 {
width: 100px;
height: 100px;
background-color: green;
float: left;
}
</style>
<body>
<div class="box1"></div>
<div class="box2"></div>
<div class="box3"></div>
</body>显示如下:

如果想要调整上面 box1、box2的顺序呢,那么需要调整结构,将 box2 写到 box1前面。
html
<body>
<div class="box2"></div>
<div class="box1"></div>
<div class="box3"></div>
</body>因为浮动元素向左或向右移动时,不会超过前边的浮动元素。
再举个栗子,下面我们设置了box1、box2左浮动,box3右浮动:
html
<style>
.box1 {
width: 300px; /* 修改了宽度 */
height: 100px;
background-color: red;
float: left;
}
.box2 {
width: 300px; /* 修改了宽度 */
height: 100px;
background-color: blue;
float: left;
}
.box3 {
width: 100px;
height: 100px;
background-color: green;
float: right;
}
</style>
<body>
<div class="box1"></div>
<div class="box2"></div>
<div class="box3"></div>
</body>显示如下,当窗口够宽时,显示如下:

当缩小窗口时,box3 会被挤到第二行:

继续缩小窗口,box2 也被挤到第二行了,虽然 box1 后面有很多空间,但是box3 也不会排列到 box1 后面。

从上面可以看出:浮动元素向左或向右浮动时,都不会超过前边的浮动元素,而且浮动元素的上边缘不会超过前面的浮动的兄弟元素的上边缘,最多就是和它一样高。
刚才我们在测试的时候,是将前面的元素浮动,脱离文档流后,后面的元素会向上移动,如果前面的元素不浮动,将后面的元素浮动呢?
html
<style>
.box1 {
width: 100px;
height: 100px;
background-color: red;
}
.box2 {
width: 100px;
height: 100px;
background-color: blue;
float: left;
}
</style>
<body>
<div class="box1"></div>
<div class="box2"></div>
</body>- 前面 box1 不浮动,后面 box2 浮动。
显示如下:

可以发现,如果浮动元素的上边是一个没有浮动的块元素,则浮动元素无法上移。
另外浮动元素不会盖住文字,文字会自动环绕在浮动元素的周围,所以我们可以利用浮动来设置文字环绕图片的效果。
举个栗子:
html
<style>
.box1 {
width: 100px;
height: 100px;
background-color: red;
float: left;
}
</style>
<body>
<div class="box1"></div>
<p>
我与父亲不相见已二年余了,我最不能忘记的是他的背影。
那年冬天,祖母死了,父亲的差使也交卸了,正是祸不单行的日子,我从北京到徐州,打算跟着父亲奔丧回家。到徐州见着父亲,看见满院狼藉的东西,又想起祖母,不禁簌簌地流下眼泪。父亲说,“事已如此,不必难过,好在天无绝人之路!”回家变卖典质,父亲还了亏空;又借钱办了丧事。这些日子,家中光景很是惨淡,一半为了丧事,一半为了父亲赋闲。丧事完毕,父亲要到南京谋事,我也要回北京念书,我们便同行。到南京时,有朋友约去游逛,勾留了一日;第二日上午便须渡江到浦口,下午上车北去。父亲因为事忙,本已说定不送我,叫旅馆里一个熟识的茶房陪我同去。他再三嘱咐茶房,甚是仔细。但他终于不放心,怕茶房不妥帖;颇踌躇了一会。其实我那年已二十岁,北京已来往过两三次,是没有甚么要紧的了。他踌躇了一会,终于决定还是自己送我去。我两回劝他不必去;他只说,“不要紧,他们去不好!”
</p>
</body>在上面设置了 box1 浮动,那么 <p> 标签将上移,但是并没有被 box1 挡住,而是环绕在 box1 周围。
显示如下:

总结:
- 设置浮动以后,元素会向父元素的左侧或右侧移动;
- 元素设置浮动以后,会完全从文档流中脱离,不再占用文档流的位置,所以元素下边的还在文档流中的元素会自动向上移动;
- 浮动元素向左或向右浮动时,都不会超过前边的浮动元素,且浮动元素的上边缘不会超过前面的浮动的兄弟元素的上边缘,最多就是和它一样高;
- 浮动元素默认不会从父元素中移出,不进行特殊设置,不会超出父元素的左、右边界;
- 如果浮动元素的上边是一个没有浮动的块元素,则浮动元素无法上移;
- 浮动元素不会盖住文字,文字会自动环绕在浮动元素的周围;
7.2 脱离文档流的特点
1 块元素
先看一下块元素浮动后的特点。
举个栗子:
html
<style>
.box1 {
background-color: red;
}
.box2 {
background-color: #CCCCCC;
height: 50px;
}
</style>
<body>
<div class="box1">foooor</div>
<div class="box2">foooor</div>
</body>显示如下:

设置 box1 浮动后:
css
.box1 {
background-color: red;
float: left;
}显示如下:

可以看到:
- 块元素浮动后,从文档流中脱离,元素不再独占页面的一行;
- 脱离文档流以后,如果不指定宽度和高度,块元素的宽度和高度默认都被内容撑开;
2 行内元素
下面看一下行内元素设置浮动后,脱离文档流后的特点。
举个栗子:
html
<style>
span {
width: 200px;
height: 200px;
background-color: red;
}
</style>
<body>
<span>这是一个span</span>
</body>行内元素不支持设置宽度和高度,所以显示如下:

设置 span 浮动后:
css
span {
width: 200px;
height: 200px;
background-color: red;
float: left;
}显示如下:

可以看到:
- 行内元素脱离文档流以后会,特点和块元素一样,所以可以设置宽度和高度了;
- 所以元素脱离文档流后,就不需要再区分块元素和行内元素了;
7.3 导航条练习
下面来进行一个练习,实现 W3school 的导航条。
显示效果:

实现上图红色框框起来的部分。
其实实现的方式不是固定的,有很多方式都可以实现,下面拘泥于当前的实现方式,当前只是提供一种思路。
1 编写框架
首先使用 HTML 实现整体的框架。
html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style/reset.css" />
<style>
</style>
</head>
<body>
<ul class="nav">
<li><a href="#">HTML/CSS</a></li>
<li><a href="#">Browser Side</a></li>
<li><a href="#">Server Side</a></li>
<li><a href="#">Programming</a></li>
<li><a href="#">XML</a></li>
<li><a href="#">Web Building</a></li>
<li><a href="#">Reference</a></li>
</ul>
</body>
</html>- 首先引入
reset.css(盒子模型章节讲过),去除默认样式。 - 然后使用
<ul>、<li>、<a>实现结构。
显示如下:

2 编写CSS样式
- 给
<ul class="nav">添加样式,设置宽高,背景颜色,屏幕居中; - 设置
<li>为浮动,水平排列,这里设置行高,可以让文字垂直居中; - 设置
<a>标签的样式。
html
<style>
.nav {
width: 1180px;
height: 48px;
background-color: #e8e7e3;
margin: 50px auto; /* 左右margin auto,设置导航条居中,盒子模型章节讲过 */
}
/* li整体布局 */
.nav li {
float: left; /* 浮动li元素 */
line-height: 48px; /* 设置行高,这样文字就垂直居中了 */
}
.nav a {
display: block; /** 设置为块元素,行高会继承自父元素,这样也就设置了a的高度和li的高度相同 **/
font-size: 18px;
color: #777777;
text-decoration: none; /* 去除下划线 */
}
</style>显示如下:

继续调整一下各个 <li> 的间距,和 <a> 标签,鼠标悬浮的效果:
css
.nav a {
display: block;
font-size: 18px;
color: #777777;
text-decoration: none;
padding: 0 38px; /* 让文字有一定的距离 */;
}
/* 超链接悬浮效果 */
.nav li a:hover {
background-color: #3f3f3f;
color: #e8e7e3;
}显示效果:

这里有一个地方需要注意:每个菜单的宽度是不一样的,单词长的,菜单也长,所以这里使用 padding 来调整 <li> 的宽度,让每个菜单中的文字有距离,但是有一个问题,padding: 0 38px; 不能保证最终各个 <li> 的宽度之和等于整个 <ul> 的宽度,如果小于最终宽度,会导致选中最后一个菜单的时候,和 <ul> 的背景不对齐。如下图:

如果出现上面这种情况,可以调整一下 <ul> 的宽度,让它等于所有 <li> 的宽度之和,我上面就是这么设置的,所以宽度是刚刚好的。
或者也可以把多出来的部分增加到最后一个菜单上,单独调整一下最后一个菜单的宽度:
css
/* 单独设置最后一个li元素中的a元素,也可以调整左右的padding,使文字更居中 */
.nav li:last-child a {
padding-right: 48px;
}最终显示效果:

最终全部代码:
html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style/reset.css" />
<style>
.nav {
width: 1190px;
height: 48px;
background-color: #e8e7e3;
margin: 50px auto; /* 左右margin auto,设置导航条居中,盒子模型章节讲过 */
}
/* li整体布局 */
.nav li {
float: left; /* 浮动li元素 */
line-height: 48px; /* 设置行高,这样文字就垂直居中了 */
}
.nav a {
display: block; /** 设置为块元素,行高会继承自父元素,也就是li **/
font-size: 18px;
color: #777777;
text-decoration: none; /* 去除下划线 */
padding: 0 38px; /* 让li元素有一定的距离 */;
}
/* 超链接悬浮效果 */
.nav li a:hover {
background-color: #3f3f3f;
color: #e8e7e3;
}
/* 单独设置最后一个li元素中的a元素 */
.nav li:last-child a {
padding-right: 48px;
}
</style>
</head>
<body>
<ul class="nav">
<li><a href="#">HTML/CSS</a></li>
<li><a href="#">Browser Side</a></li>
<li><a href="#">Server Side</a></li>
<li><a href="#">Programming</a></li>
<li><a href="#">XML</a></li>
<li><a href="#">Web Building</a></li>
<li><a href="#">Reference</a></li>
</ul>
</body>
</html>7.4 布局练习
下面实现一个下面这样的布局:

- 上面是导航栏、中间是内容区域、底部是footer;
- 中间的内容分为左、中、右三个部分。
1 编写框架
html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style/reset.css" />
<style>
header {
width: 1000px;
height: 80px;
background-color: lightskyblue;
margin: 0 auto;
}
main {
width: 1000px;
height: 500px;
background-color: lightcoral;
margin: 10px auto;
}
footer {
width: 1000px;
height: 80px;
background-color: lightgreen;
margin: 0 auto;
}
</style>
</head>
<body>
<!-- 头部 -->
<header></header>
<!-- 中间主要区域 -->
<main>
<!-- 左侧区域 -->
<nav></nav>
<!-- 中间区域 -->
<section></section>
<!-- 右侧区域 -->
<aside></aside>
</main>
<!-- footer -->
<footer></footer>
</body>
</html>- 在上面使用了各个语义标签定义了各个布局区域,当然你所有区域都使用 div 也是可以的;
- 单独定义区域,是显示不出任何内容的,所以给各个区域设置了大小、背景颜色、并设置了居中,并给中间的区域设置了上下的 margin;
显示如下:

2 继续编写CSS样式
下面继续编写 CSS,设置中间部分左、中、右三个区域的布局
css
main > nav {
width: 200px;
height: 100%;
background-color: lightcoral;
float: left;
}
main > section {
width: 600px;
height: 100%;
background-color: lightcyan;
float: left;
}
main > aside {
width: 200px;
height: 100%;
background-color: lightyellow;
float: left;
}- 设置三个区域的宽度;设置高度和中间区域的高度一样 100%;
- 设置三个区域都是左浮动,横向排列
显示如下:

设置一下中间左、中、右三个区域的间隔。设置中间部分左右的间隔即可,不过还需要调整一下宽度,否则超过了整个区域的宽度,右侧区域会被挤下去:
css
main > section {
width: 580px; /* 总宽度减去margin的宽度 */
height: 100%;
background-color: lightcyan;
float: left;
margin: 0 10px; /* 左右各10px */
}最终显示效果:

最终代码:
html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style/reset.css" />
<style>
/* 设置头部区域样式 */
header {
width: 1000px;
height: 80px;
background-color: lightpink;
margin: 0 auto;
}
/* 设置内容区域样式 */
main {
width: 1000px;
height: 500px;
background-color: lightgray;
margin: 10px auto;
}
main > nav {
width: 200px;
height: 100%;
background-color: lightcoral;
float: left;
}
main > section {
width: 580px; /* 总宽度减去margin的宽度 */
height: 100%;
background-color: lightcyan;
float: left;
margin: 0 10px; /* 左右各10px */
}
main > aside {
width: 200px;
height: 100%;
background-color: lightyellow;
float: left;
}
/* 设置底部区域样式 */
footer {
width: 1000px;
height: 80px;
background-color: lightgreen;
margin: 0 auto;
}
</style>
</head>
<body>
<!-- 头部 -->
<header></header>
<!-- 中间主要区域 -->
<main>
<!-- 左侧区域 -->
<nav></nav>
<!-- 中间区域 -->
<section></section>
<!-- 右侧区域 -->
<aside></aside>
</main>
<!-- footer -->
<footer></footer>
</body>
</html>在现代 CSS 中,浮动已经不再是布局的首选方法,更多的是使用 Flexbox 或 Grid 来处理布局,后面再讲。
另外上面的布局存在一个问题,就是中间内容区域的高度是定死了,就是 500px,这样如果内容区域的内容很多,将无法完整显示内容或只能使用滚动条,正常情况下应该是内容区域的高度随着内容自动扩展。但是这里又不能不定死内容区域的高度,因为其中的子元素是浮动的,这里涉及的一个问题就是父元素的高度塌陷问题,下一个章节讲。