# CSS3教程 - 7 浮动

我们之前学的布局都是垂直方向的布局,现在开始学习水平方向的布局——浮动。

# 7.1 浮动的使用

通过浮动可以使一个元素向其父元素的左侧或右侧移动。

使用 float 属性来设置于元素的浮动:

  • float: left;:将元素浮动到父元素的左侧;

  • float: right;:将元素浮动到父元素的右侧;

  • float: none;:取消浮动,默认值。


举个栗子:

<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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

上面是 box1 和 box2 都不浮动,效果如下:

都不浮动的情况下,一个元素在其父元素中,水平布局必须要满足以下的等式:

margin-left + border-left + padding-left + width + padding-right + border-right + margin-right = 其父元素的宽度

虽然 box1 右侧有很大的空间,但是根据上面的公式,右侧实际上都是 box1的 margin-right,所以 box2 只能在下面。

下面设置让 box1左浮动

.box1 {
  width: 100px;
  height: 100px;
  background-color: red;
  float: left;
}
1
2
3
4
5
6

显示如下:

我们会发现,box1 左浮动后,它的位置没有变,但是 box2 向上移动到了 box1 下面。这是为什么呢?

这是因为 box1 设置左浮动后,box1 会向父元素的左侧移动,所以它移动到了父元素的最左侧。同时一个元素设置了浮动以后,它就脱离了文档流,不再占据文档流中的位置,所以 box2 会向上移动。

下面设置让 box1 右浮动

.box1 {
  width: 100px;
  height: 100px;
  background-color: red;
  float: right;
}
1
2
3
4
5
6

显示如下:

box1 移动到了父元素的最右侧,box1 脱离了文档流后, box2 会向上移动。

通过上面可以发现:

  • 元素设置浮动以后,水平布局的等式便不需要强制成立;
  • 设置浮动以后,元素会向父元素的左侧或右侧移动
  • 元素设置浮动以后,会完全从文档流中脱离,不再占用文档流的位置,所以元素下边的还在文档流中的元素会自动向上移动
  • 浮动元素默认不会从父元素中移出,不进行特殊设置,不会超出父元素的左、右边界。

所以如果要实现水平方向的布局,只需要让元素都浮动起来排列:

<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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

显示如下:

如果想要调整上面 box1、box2的顺序呢,那么需要调整结构,将 box2 写到 box1前面。

<body>
  <div class="box2"></div>
  <div class="box1"></div>
  <div class="box3"></div>
</body>
1
2
3
4
5

因为浮动元素向左或向右移动时,不会超过前边的浮动元素。


再举个栗子,下面我们设置了box1、box2左浮动,box3右浮动:

<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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

显示如下,当窗口够宽时,显示如下:

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

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

从上面可以看出:浮动元素向左或向右浮动时,都不会超过前边的浮动元素,而且浮动元素的上边缘不会超过前面的浮动的兄弟元素的上边缘,最多就是和它一样高。


刚才我们在测试的时候,是将前面的元素浮动,脱离文档流后,后面的元素会向上移动,如果前面的元素不浮动,将后面的元素浮动呢?

<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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  • 前面 box1 不浮动,后面 box2 浮动。

显示如下:

可以发现,如果浮动元素的上边是一个没有浮动的块元素,则浮动元素无法上移。


另外浮动元素不会盖住文字,文字会自动环绕在浮动元素的周围,所以我们可以利用浮动来设置文字环绕图片的效果。

举个栗子:

<style>
  .box1 {
    width: 100px;
    height: 100px;
    background-color: red;
    float: left;
  }
</style>

<body>
  <div class="box1"></div>
  <p>
    我与父亲不相见已二年余了,我最不能忘记的是他的背影。
    那年冬天,祖母死了,父亲的差使也交卸了,正是祸不单行的日子,我从北京到徐州,打算跟着父亲奔丧回家。到徐州见着父亲,看见满院狼藉的东西,又想起祖母,不禁簌簌地流下眼泪。父亲说,“事已如此,不必难过,好在天无绝人之路!”回家变卖典质,父亲还了亏空;又借钱办了丧事。这些日子,家中光景很是惨淡,一半为了丧事,一半为了父亲赋闲。丧事完毕,父亲要到南京谋事,我也要回北京念书,我们便同行。到南京时,有朋友约去游逛,勾留了一日;第二日上午便须渡江到浦口,下午上车北去。父亲因为事忙,本已说定不送我,叫旅馆里一个熟识的茶房陪我同去。他再三嘱咐茶房,甚是仔细。但他终于不放心,怕茶房不妥帖;颇踌躇了一会。其实我那年已二十岁,北京已来往过两三次,是没有甚么要紧的了。他踌躇了一会,终于决定还是自己送我去。我两回劝他不必去;他只说,“不要紧,他们去不好!”
  </p>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

在上面设置了 box1 浮动,那么 <p> 标签将上移,但是并没有被 box1 挡住,而是环绕在 box1 周围。

显示如下:


总结:

  1. 设置浮动以后,元素会向父元素的左侧或右侧移动
  2. 元素设置浮动以后,会完全从文档流中脱离,不再占用文档流的位置,所以元素下边的还在文档流中的元素会自动向上移动
  3. 浮动元素向左或向右浮动时,都不会超过前边的浮动元素,且浮动元素的上边缘不会超过前面的浮动的兄弟元素的上边缘,最多就是和它一样高;
  4. 浮动元素默认不会从父元素中移出,不进行特殊设置,不会超出父元素的左、右边界;
  5. 如果浮动元素的上边是一个没有浮动的块元素,则浮动元素无法上移;
  6. 浮动元素不会盖住文字,文字会自动环绕在浮动元素的周围;

# 7.2 脱离文档流的特点

# 1 块元素

先看一下块元素浮动后的特点。

举个栗子:

<style>
  .box1 {
    background-color: red;
  }

  .box2 {
    background-color: #CCCCCC;
    height: 50px;
  }
</style>

<body>
  <div class="box1">foooor</div>
  <div class="box2">foooor</div>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

显示如下:

设置 box1 浮动后:

.box1 {
  background-color: red;
  float: left;
}
1
2
3
4

显示如下:

可以看到:

  • 块元素浮动后,从文档流中脱离,元素不再独占页面的一行;
  • 脱离文档流以后,如果不指定宽度和高度,块元素的宽度和高度默认都被内容撑开;

# 2 行内元素

下面看一下行内元素设置浮动后,脱离文档流后的特点。

举个栗子:

<style>
  span {
    width: 200px;
    height: 200px;
    background-color: red;
  }
</style>

<body>
  <span>这是一个span</span>
</body>
1
2
3
4
5
6
7
8
9
10
11

行内元素不支持设置宽度和高度,所以显示如下:

设置 span 浮动后:

span {
  width: 200px;
  height: 200px;
  background-color: red;
  float: left;
}
1
2
3
4
5
6

显示如下:

可以看到:

  • 行内元素脱离文档流以后会,特点和块元素一样,所以可以设置宽度和高度了;
  • 所以元素脱离文档流后,就不需要再区分块元素和行内元素了;

# 7.3 导航条练习

下面来进行一个练习,实现 W3school 的导航条。

显示效果:

实现上图红色框框起来的部分。

其实实现的方式不是固定的,有很多方式都可以实现,下面拘泥于当前的实现方式,当前只是提供一种思路。

# 1 编写框架

首先使用 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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  • 首先引入 reset.css (盒子模型章节讲过),去除默认样式。
  • 然后使用 <ul><li><a> 实现结构。

显示如下:

# 2 编写CSS样式

  • <ul class="nav"> 添加样式,设置宽高,背景颜色,屏幕居中;
  • 设置 <li> 为浮动,水平排列,这里设置行高,可以让文字垂直居中;
  • 设置 <a> 标签的样式。
<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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

显示如下:

继续调整一下各个 <li> 的间距,和 <a> 标签,鼠标悬浮的效果:

.nav a {
  display: block;
  font-size: 18px;
  color: #777777;
  text-decoration: none; 
  padding: 0 38px;  /* 让文字有一定的距离 */;
}

/* 超链接悬浮效果 */
.nav li a:hover {
  background-color: #3f3f3f;
  color: #e8e7e3;
}
1
2
3
4
5
6
7
8
9
10
11
12
13

显示效果:

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

如果出现上面这种情况,可以调整一下 <ul> 的宽度,让它等于所有 <li> 的宽度之和,我上面就是这么设置的,所以宽度是刚刚好的。

或者也可以把多出来的部分增加到最后一个菜单上,单独调整一下最后一个菜单的宽度:

/* 单独设置最后一个li元素中的a元素,也可以调整左右的padding,使文字更居中 */
.nav li:last-child a {
  padding-right: 48px;
}
1
2
3
4

最终显示效果:

最终全部代码:

<!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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

# 7.4 布局练习

下面实现一个下面这样的布局:

  • 上面是导航栏、中间是内容区域、底部是footer;
  • 中间的内容分为左、中、右三个部分。

# 1 编写框架

<!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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
  • 在上面使用了各个语义标签定义了各个布局区域,当然你所有区域都使用 div 也是可以的;
  • 单独定义区域,是显示不出任何内容的,所以给各个区域设置了大小、背景颜色、并设置了居中,并给中间的区域设置了上下的 margin;

显示如下:

# 2 继续编写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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  • 设置三个区域的宽度;设置高度和中间区域的高度一样 100%;
  • 设置三个区域都是左浮动,横向排列

显示如下:

设置一下中间左、中、右三个区域的间隔。设置中间部分左右的间隔即可,不过还需要调整一下宽度,否则超过了整个区域的宽度,右侧区域会被挤下去:

main > section {
  width: 580px;  /* 总宽度减去margin的宽度 */
  height: 100%;
  background-color: lightcyan;
  float: left;
  margin: 0 10px;  /* 左右各10px */
}
1
2
3
4
5
6
7

最终显示效果:

最终代码:

<!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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

在现代 CSS 中,浮动已经不再是布局的首选方法,更多的是使用 Flexbox 或 Grid 来处理布局,后面再讲。

另外上面的布局存在一个问题,就是中间内容区域的高度是定死了,就是 500px,这样如果内容区域的内容很多,将无法完整显示内容或只能使用滚动条,正常情况下应该是内容区域的高度随着内容自动扩展。但是这里又不能不定死内容区域的高度,因为其中的子元素是浮动的,这里涉及的一个问题就是父元素的高度塌陷问题,下一个章节讲。