# CSS3教程 - 15 弹性盒模型

前面学习了浮动、定位的方式来帮助我们布局,下面来学习 CSS3 中一个新的布局方式:弹性盒。浮动的定位方式有很多的副作用,而弹性盒可以替代浮动。

CSS 中的弹性盒(Flexbox)是一个非常强大且灵活的布局模型,可以提供更简单的方式来设计和排列页面元素,尤其是处理复杂的布局时。尤其是在移动端,每个手机的宽度都不同,通过弹性盒,可以使得子元素在父容器中能够按需自动分配空间并对齐,并使元素具有”弹性“,可以根据页面大小的改变而改变。

# 15.1 基本概念

弹性盒布局基于父容器和子元素的关系。父容器被称为 弹性容器(flex container),而容器中的每个直接子元素称为 弹性元素(弹性项)(flex item)。

我们首先需要给父容器设置 display: flexdisplay: inline-flex 属性,将父元素变为弹性容器,这样就能够启用弹性布局。

  • display: flex :将父元素设置为块级弹性容器;
  • display: inline-flex :将父元素设置为行内弹性容器;

父元素设置为弹性容器,它的子元素(直接后代元素)就变成了弹性元素,弹性元素会变为块元素,即使是行内元素也会变成块元素。

display: inline-flex; 用的比较少,因为如果想让弹性容器和弹性容器之间像块元素一样横向排列,外面再套一个弹性容器就好了,一个元素可以同时是弹性容器和弹性元素。


举个栗子:

<!DOCTYPE html>
<html>
  <head>
    <style>
      .outer {
        width: 600px;
        border: 5px solid red;
        display: flex;  /* 设置父元素为块级弹性容器 */
      }

      .outer div {
        width: 100px;
        height: 100px;
      }

      .box1 {
        background-color: lightblue;
      }
      .box2 {
        background-color: lightpink;
      }
      .box3 {
        background-color: lightgreen;
      }

    </style>
  </head>

  <body>
    <div class="outer">
      <div class="box1">1</div>
      <div class="box2">2</div>
      <div class="box3">3</div>
    </div>
  </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
  • 在上面的代码中,父容器中包含了三个子容器,然后通过 display: flex; 设置父容器为块级弹性容器。
  • 子元素变为水平排列了。

显示如下:

# 15.2 弹性容器的属性

下面来介绍一下弹性容器相关的属性。

# 1 排列方式

上面设置了父元素为弹性容器后,子元素默认就变成了水平从左向右排列,通过 flex-direction 可以设置子元素的排列方式。

可选值有:

  • row :默认值,弹性元素在容器中水平排列,自左向右;
  • row-reverse :弹性元素在容器中水平排列,自右向左;
  • column :弹性元素在容器中垂直排列,自上向下;
  • column-reverse :弹性元素在容器中垂直排列,自下向上;

举个栗子,给父元素弹性容器设置即可:

.outer {
  width: 600px;
  border: 5px solid red;
  
  display: flex;  /* 设置父元素为块级弹性容器 */
  flex-direction: row;  /* 设置子元素排列方式 */
}
1
2
3
4
5
6
7

各个值的显示效果如下:

  • flex-direction: row;

  • flex-direction: row-reverse:

  • flex-direction: column;

  • flex-direction: column-reverse;

可以看到排列非常的方便。

# 2 主轴与侧轴

在讲解后面的知识之前先讲解两个概念:主轴侧轴

  • 主轴:弹性元素的排列方向称为主轴。

    flex-direction: row; 时,主轴是水平方向,从左到右;当 flex-direction: row-reverse; 时,主轴是水平方向,从右到左;

    flex-direction: column; 时,主轴是垂直方向,从上到下;当 flex-direction: column-reverse; 时,主轴是垂直方向,从下到上;

  • 侧轴:与主轴垂直方向的称为侧轴,也叫辅轴交叉轴

    flex-direction: row(主轴是横向),则 侧轴是纵向(从上到下)。

    如果 flex-direction: column(主轴是纵向),则 侧轴是横向(从左到右)。

也就是说主轴以及方向是由 flex-direction 属性决定。

# 3 主轴换行

当父元素在主轴上的尺寸不足以容纳子元素时,各个子元素会缩小主轴上的尺寸,以适应父容器在主轴上的尺寸。

举个栗子:

<!DOCTYPE html>
<html>
  <head>
    <style>
      .outer {
        width: 250px;
        height: 50px;
        border: 5px solid red;
        display: flex;  /* 设置父元素为块级弹性容器 */
        flex-direction: row;  /* 横向排列 */
      }

      .outer div {
        width: 100px;
        height: 100px;
      }

      .box1 {
        background-color: lightblue;
      }
      .box2 {
        background-color: lightpink;
      }
      .box3 {
        background-color: lightgreen;
      }

    </style>
  </head>

  <body>
    <div class="outer">
      <div class="box1">1</div>
      <div class="box2">2</div>
      <div class="box3">3</div>
    </div>
  </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
  • 上面各个子元素的宽为100px,总共 300px,大于父元素的宽度为 250px,主轴为水平的,所以会缩小各个子元素的宽度;
  • 各个子元素的高度是 100px,大于父元素的高度 50px,但是各个元素的高度不会缩小,而是从父元素中溢出;

显示如下:


可以设置弹性容器的 flex-wrap 属性,让子元素在弹性容器中自动换行。

flex-wrap 的可选值:

  • nowrap :默认值,元素不会自动换行;
  • wrap :元素沿着侧轴方向自动换行;
  • wrap-reverse :元素沿着侧轴反方向换行,正常换行是从下一行开始,这个换行是从上一行重新开始;

举个栗子:

.outer {
  width: 250px;
  border: 5px solid red;

  display: flex;  /* 设置父元素为块级弹性容器 */
  flex-direction: row;  /* 横向排列 */
  flex-wrap: wrap;  /* 子元素换行 */
}
1
2
3
4
5
6
7
8
  • 上面通过 flex-wrap: wrap; 设置了自动换行;

显示如下:

如果设置为 flex-wrap: wrap-reverse; ,则显示如下:


flex-wrapflex-direction 有一个简写属性 flex-flow

/* 简写属性 */
flex-flow: row wrap;
1
2

了解一下。

# 4 主轴对齐方式

弹性容器的 justify-content 属性可以控制元素在主轴的对齐方式。

举个栗子:

<!DOCTYPE html>
<html>
  <head>
    <style>
      .outer {
        width: 600px;
        border: 5px solid red;

        /* 弹性容器 */
        display: flex;
        flex-direction: row;
        justify-content: center;  /* 设置在主轴的对齐方式 */
      }

      .outer div {
        width: 100px;
        height: 100px;
      }

      .box1 {
        background-color: lightblue;
      }
      .box2 {
        background-color: lightpink;
      }
      .box3 {
        background-color: lightgreen;
      }

    </style>
  </head>

  <body>
    <div class="outer">
      <div class="box1">1</div>
      <div class="box2">2</div>
      <div class="box3">3</div>
    </div>
  </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
  • 上面设置了 justify-content: center; 也就是元素会在主轴上居中对齐。

显示如下:


justify-content 的可选值有:

  • flex-start:默认值,子元素从起始位置开始排列,剩余的空白位置都在主轴的最后面;

  • flex-end :和 flex-start 相反,子元素从容器的结束位置对齐,剩余的空白位置都在最前面。

  • center :子元素在容器中居中对齐,空白位置在两边。

  • space-between :子元素之间的空白间距相等,首尾没有间隔。

  • space-around :子元素之间的空白间距相等,首尾都有间隔,首尾间距是元素间距的一半。

  • space-evenly :子元素之间的间隔相等,首尾之间也有相等的间隔。

# 5 侧轴对齐方式

弹性容器的 align-items 属性可以控制子元素在侧轴上的对齐方式。

首先看一下默认效果:

<!DOCTYPE html>
<html>
  <head>
    <style>
      .outer {
        width: 600px;
        height: 300px;
        border: 5px solid red;

        /* 弹性容器 */
        display: flex;  
        flex-direction: row;
      }

      .outer div {
        width: 100px;
      }

      .box1 {
        background-color: lightblue;
      }
      .box2 {
        background-color: lightpink;
      }
      .box3 {
        background-color: lightgreen;
      }

    </style>
  </head>

  <body>
    <div class="outer">
      <div class="box1">1</div>
      <div class="box2">2</div>
      <div class="box3">3</div>
    </div>
  </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
  • 上面没有设置什么效果,设置了父元素为弹性盒而已。
  • 另外去掉了子元素的高度,此时元素在侧轴上的尺寸是撑满父容器的。

显示如下:


我们可以通过弹性容器的 align-items 属性,设置子元素在侧轴上的对齐方式。

举个例子:

.outer {
  width: 600px;
  height: 300px;
  border: 5px solid red;

  /* 弹性容器 */
  display: flex;  
  flex-direction: row;
  align-items: stretch;  /* 元素在侧轴上的对齐方式 */
}
1
2
3
4
5
6
7
8
9
10
  • align-items 的默认值就是 stretch ,所以设置完没有效果,就是将子元素在侧轴方向上拉伸填满容器。

其他的取值及效果如下:

  • flex-start :子元素在侧轴起始位置对齐:

  • flex-end :子元素在侧轴结束位置对齐,此时侧轴从上到下,结束位置在下,所以元素在底部:

  • center :子元素在侧轴方向上居中对齐:

  • baseline :基线对齐,用的比较少:

# 6 水平垂直居中

通过上面主轴和侧轴的对齐方式,如果让子元素水平和垂直居中就非常简单了。

直接代码如下:

<!DOCTYPE html>
<html>
  <head>
    <style>
      .outer {
        width: 600px;
        height: 200px;
        border: 5px solid red;

        /* 弹性容器 */
        display: flex;  
        flex-direction: row;

        justify-content: center;  /* 主轴居中 */
        align-items: center;  /* 侧轴居中 */
      }

      .box1 {
        background-color: lightblue;
      }

    </style>
  </head>

  <body>
    <div class="outer">
      <div class="box1">www.foooor.com</div>
    </div>
  </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
  • 直接主轴居中、侧轴居中即可。

显示如下:

# 7 侧轴多行对齐方式

弹性容器的 align-content 可以控制多行项目在侧轴方向上的对齐方式,只有在 flex-wrap: wrap; 被启用并且容器中有多行内容时,align-content 才会有效。

先看一下默认效果:

<!DOCTYPE html>
<html>
  <head>
    <style>
      .outer {
        width: 600px;
        height: 200px;
        border: 5px solid red;

        /* 弹性容器 */
        display: flex;  
        flex-direction: row;
        flex-wrap: wrap;  /* 设置主轴自动换行 */
        align-content: stretch;   /* 多行元素在侧轴上的对齐方式 */
      }

      .outer div {
        width: 200px;
      }

      .box1 {
        background-color: lightblue;
      }
      .box2 {
        background-color: lightpink;
      }
      .box3 {
        background-color: lightgreen;
      }
    </style>
  </head>

  <body>
    <div class="outer">
      <div class="box1">1</div>
      <div class="box2">2</div>
      <div class="box3">3</div>
      <div class="box2">4</div>
      <div class="box3">5</div>
      <div class="box1">6</div>
      <div class="box1">7</div>
      <div class="box2">8</div>
    </div>
  </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
  • 上面设置了主轴自动换行,并设置了 align-content: stretch; 表示每一行会尽量拉伸填满容器。其实是默认值,设置不设置效果是一样的。

显示如下:


align-content 的可选值及效果如下:

  • stretch :行的高度会被拉伸,填满容器。

    效果如上。

  • flex-start :行对齐容器的顶部,可能会有多余的空间分布在底部:

  • flex-end :行对齐容器的底部,可能会有多余的空间分布在顶部:

  • center :行会在容器中居中:

  • space-between :行之间的间隔相等。

  • space-around :行之间的间隔相等,首尾有间隔,行间距是首尾间距的两倍:

  • space-evenly :行之间的间隔相等,首尾有间隔,行间距等于首尾间距:


align-contentalign-items 的区别

  • align-items:用于控制 单行 项目在交叉轴方向上的对齐方式。
  • align-content:用于控制 多行 项目在交叉轴方向上的对齐方式。

# 15.3 弹性元素的属性

下面来介绍弹性元素相关的属性。

# 1 align-self

align-self 属性允许我们单独控制某个 弹性元素 在交叉轴(侧轴)方向上的对齐方式。它会覆盖弹性容器的 align-items 设置,为特定的子项目提供独立的对齐方式。

align-self 的可选值如下:

  • auto :默认值,该元素采用父容器的 align-items 设置值;
  • stretch :该元素将被拉伸以填满容器的交叉轴方向;
  • flex-start :该元素将对齐到容器的侧轴起点;
  • flex-end :该元素将对齐到容器的侧轴终点;
  • center :该元素将会在侧轴方向上居中对齐;
  • baseline :该元素将对齐到容器中项目的基线。

举个栗子:

<!DOCTYPE html>
<html>
  <head>
    <style>
      .outer {
        width: 600px;
        height: 200px;
        border: 5px solid red;

        /* 弹性容器 */
        display: flex;  
        align-items: center;   /* 子元素在侧轴居中对齐 */
      }

      .outer div {
        width: 100px;
      }

      .box1 {
        align-self: flex-start;  /* 单独指定对齐方式 */
        background-color: lightblue;
      }
      .box2 {
        background-color: lightpink;
      }
      .box3 {
        background-color: lightgreen;
      }
    </style>
  </head>

  <body>
    <div class="outer">
      <div class="box1">1</div>
      <div class="box2">2</div>
      <div class="box3">3</div>
    </div>
  </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
  • 在上面的代码中,设置了弹性容器中元素在侧轴的对齐方式为居中对齐。
  • 但是单独设置了 box1 在侧轴的对齐方式为侧轴的起点。

显示如下:

其他的对齐方式就不演示了,参考 align-items 的对齐方式即可,只是针对单个元素设置而已。

# 2 伸展系数

弹性盒模型,可以让元素可以具有弹性,flex-grow 可以指定弹性元素的伸展系数,当父元素有多余的空间时,可以指定子元素如何伸展,默认值为 0,也就是不伸展。

通过 flex-grow 可以为各个子元素指定对父元素剩余空间的分配。

举个栗子:

<!DOCTYPE html>
<html>
  <head>
    <style>
      .outer {
        width: 600px;
        border: 5px solid red;
        display: flex;  /* 设置父元素为块级弹性容器 */
      }

      .outer div {
        width: 100px;
        height: 100px;
      }

      .box1 {
        background-color: lightblue;
        flex-grow: 1;  /* 指定伸展系数 */
      }
      .box2 {
        background-color: lightpink;
        flex-grow: 2;   /* 指定伸展系数 */
      }
      .box3 {
        background-color: lightgreen;
        flex-grow: 3;   /* 指定伸展系数 */
      }

    </style>
  </head>

  <body>
    <div class="outer">
      <div class="box1">1</div>
      <div class="box2">2</div>
      <div class="box3">3</div>
    </div>
  </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
  • 上面父元素宽度为600px,每个元素为100px,还剩余300px;那么就由三个元素分配剩余的 300px。
  • box1 的 flex-grow: 1; ,则剩余的 300px 占用1份,box3 的 flex-grow: 3; 则占用三份;值越大,伸展的越大。

显示如下:

# 3 缩减系数

flex-shrink 属性用于指定弹性元素的收缩系数。当父元素中的空间不足以容纳所有的子元素时,如何对子元素进行收缩。默认值为 1,各个元素都同比例收缩。如果设置为 0,那么就不会收缩,子元素会从父元素溢出。

举个栗子:

<!DOCTYPE html>
<html>
  <head>
    <style>
      .outer {
        width: 300px;
        border: 5px solid red;
        display: flex;  /* 设置父元素为块级弹性容器 */
      }

      .outer div {
        width: 200px;
        height: 200px;
      }

      .box1 {
        background-color: lightblue;
        flex-shrink: 1;  /* 指定收缩系数 */
      }
      .box2 {
        background-color: lightpink;
        flex-shrink: 2;  /* 指定收缩系数 */
      }
      .box3 {
        background-color: lightgreen;
        flex-shrink: 3;  /* 指定收缩系数 */
      }

    </style>
  </head>

  <body>
    <div class="outer">
      <div class="box1">1</div>
      <div class="box2">2</div>
      <div class="box3">3</div>
    </div>
  </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
  • 上面指定了每个子元素的宽度是 200px,共600px,父元素总共才300px,所以父元素无法容纳子元素,会对子元素进行收缩。
  • 指定了 box1 为 flex-shrink: 1; 收缩最小,box3 为 flex-shrink: 3; 收缩最大。

显示如下:

# 4 基础长度

flex-basis 指定的是元素在主轴上的基础长度,如果主轴是横向的,则指定的是元素的宽度;如果主轴是垂直的,则指定的是元素的高度。默认值是 auto,表示参考元素自身的高度或宽度。

如果传递了一个具体的数值,则 flex-basis 会覆盖元素在主轴上的尺寸,也就是会覆盖宽度或高度。一般用的比较少,都设置为 auto

举个栗子:

<!DOCTYPE html>
<html>
  <head>
    <style>
      .outer {
        width: 600px;
        height: 200px;
        border: 5px solid red;

        /* 弹性容器 */
        display: flex;  
      }

      .outer div {
        width: 100px;
        height: 100px;
      }

      .box1 {
        flex-basis: 200px;  /* 基础长度 */
        background-color: lightblue;
      }
      .box2 {
        background-color: lightpink;
      }
      .box3 {
        background-color: lightgreen;
      }
    </style>
  </head>

  <body>
    <div class="outer">
      <div class="box1">1</div>
      <div class="box2">2</div>
      <div class="box3">3</div>
    </div>
  </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
  • 上面针对 box1 设置了基础长度,主轴为横向,那么会覆盖元素的宽度。

显示如下:

# 5 复合属性

flex-growflex-shrinkflex-basis 三个属性一般很少单独使用,而是使用 flex 复合属性来设置这三个属性。

flex 可以设置弹性元素三个样式,语法:

flex: 增长系数 缩减系数 基础长度
1

flex 属性除了可以像上面设置三个值,还可以设置三个可选值:

  • initial :相当于 flex: 0 1 auto; 默认值,不会放大,会自动缩小;
  • auto:相当于 flex: 1 1 auto; 元素自动放大缩小;
  • none:相当于 flex: 0 0 auto; 弹性元素没有弹性。

# 6 排列顺序

order 属性可以控制弹性元素的排列顺序。order 属性是一个 整数 值,用于指定弹性项目的显示顺序。数字越小,项目越先显示,负值也有效。如果多个项目有相同的 order 值,它们将按照它们在 HTML 中的顺序进行排列。

举个栗子:

<!DOCTYPE html>
<html>
  <head>
    <style>
      .outer {
        width: 600px;
        height: 200px;
        border: 5px solid red;

        /* 弹性容器 */
        display: flex;  
      }

      .outer div {
        width: 100px;
        height: 100px;
      }

      .box1 {
        order: 2;  /* 设置显示顺序 */
        background-color: lightblue;
      }
      .box2 {
        order: 0;  /* 设置显示顺序 */
        background-color: lightpink;
      }
      .box3 {
        order: 1;  /* 设置显示顺序 */
        background-color: lightgreen;
      }
    </style>
  </head>

  <body>
    <div class="outer">
      <div class="box1">1</div>
      <div class="box2">2</div>
      <div class="box3">3</div>
    </div>
  </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
  • 上面三个弹性元素,默认排序是 1、2、3,但是通过 order 属性,调整了显示顺序为 2、3、1。

显示如下:

# 15.4 菜单练习

下面使用弹性盒来实现浮动时候实现的菜单:

思路:

  • 直接将 <ul> 设置为弹性容器, <li> 就变成弹性元素了;
  • 使用 flex: auto; 将弹性元素设置为自动伸缩,这个时候布局就差不多了;
  • 然后设置行高和居中,微调样式即可。

完整代码如下:

<!DOCTYPE html>
<html>
  <head>
    <style>
      * {  /* 重置样式 */
        padding: 0;
        margin: 0;
        /* 去掉li元素前面的黑点 */
        list-style: none;
      }

      .nav {
        width: 1190px;
        height: 48px;
        background-color: #e8e7e3;
        margin: 50px auto; /* 设置导航条居中 */

        /* 弹性盒容器 */
        display: flex;
      }

      .nav li {
        flex: auto;  /* 弹性元素自动缩放 */
        line-height: 48px;  /* 设置行高 */
        text-align: center;    /* 文字水平居中 */
      }

      .nav a {
        display: block; /** 设置为块元素,行高会继承自父元素,也就是li **/
        font-size: 18px;
        color: #777777;
        text-decoration: none; /* 去除下划线 */
      }

      /* 超链接悬浮效果 */
      .nav li a:hover {
        background-color: #3f3f3f;
        color: #e8e7e3;
      }
    </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
52
53
54

可以看到弹性盒布局非常的方便。