flex布局教程

1.flex布局是什么?

css3引入了一种新的布局模式,叫做Flexbox布局,即伸缩布局和(Flexible Box)模型,很多地方又称为弹性盒模型,我们下面都叫弹性盒模型,它可以用来提供一个更加有效的方式制定、调整和分布一个容器里的项目布局

css中的布局方式总结:

块布局 
行内布局
表格布局
定位布局
FlexBox布局(css3新引入)

2.掌握Flexbox模型中的术语

2.1.主轴和侧轴

主轴和侧轴你可以简单的理解为水平和垂直方向上的两根轴,类似x轴和y轴,默认情况下主轴是水平方向的,但是可以设置,将主轴设置成垂直方向,主轴外的另一轴就是侧轴

2.2.伸缩容器和伸缩项目

伸缩容器就是通过display属性设置为flex或者inline-flex的容器(盒子),伸缩项目就是这个伸缩容器下面的子元素

2.3.新版本和老版本

Flexbox布局语法规范主要分为三种:

旧版本:2009年版本,使用display:box或者display:inline-box

混合版本: 2011年版本,使用display:flexbox 或者display:inlne-flexbox

最新版本: 使用display:flex 或者 display:inlne-flex

查看Flexbox兼容性支持情况

https://caniuse.com/#search=flexbox

2.4.flex初体验

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      .box {
        height: 100px;
        background-color: green;
        display: flex;
      }
      .box div {
        height: 80px;
        width: 80px;
        margin: auto;
        background-color: orangered;
      }
    </style>
  </head>
  <body>
    <div class="box">
      <div class="box-item_1">1</div>
      <div class="box-item_2">2</div>
      <div class="box-item_3">3</div>
      <div class="box-item_4">4</div>
    </div>
  </body>
</html>

3.容器相关属性

容器常用属性

flex-direction
flex-wrap
flex-flow
justify-content
align-items
align-content

3.1.flex-direction

这个属性决定主轴的方向(即项目的排列方向)

.box {
  flex-direction: row | row-reverse | column | column-reverse;
}
row(默认值):主轴为水平方向,起点在左端。
row-reverse:主轴为水平方向,起点在右端。
column:主轴为垂直方向,起点在上沿。
column-reverse:主轴为垂直方向,起点在下沿

实例:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .box {
        display: flex;
        flex-direction: row;
      }
      .box div {
        width: 100px;
        height: 100px;
        text-align: center;
        line-height: 100px;
        font-size: 20px;
      }
      .box div:nth-of-type(1) {
        background-color: red;
      }
      .box div:nth-of-type(2) {
        background-color: green;
      }
      .box div:nth-of-type(3) {
        background-color: blueviolet;
      }
      .box div:nth-of-type(4) {
        background-color: blue;
      }
    </style>
  </head>
  <body>
    <div class="box">
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
    </div>
  </body>
</html>

3.2.flex-wrap属性

这个属性主要作用是规定当一行放不下的时候如何换行

.box{
  flex-wrap: nowrap | wrap | wrap-reverse;
}
nowrap(默认):不换行。
wrap:换行,第一行在上方。
wrap-reverse:换行,第一行在下方。

实例:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .box {
        display: flex;
        flex-direction: row;
        width: 200px;
        flex-wrap: wrap-reverse;
      }
      .box div {
        width: 100px;
        height: 100px;
        text-align: center;
        line-height: 100px;
        font-size: 20px;
      }
      .box div:nth-of-type(1) {
        background-color: red;
      }
      .box div:nth-of-type(2) {
        background-color: green;
      }
      .box div:nth-of-type(3) {
        background-color: blueviolet;
      }
      .box div:nth-of-type(4) {
        background-color: blue;
      }
    </style>
  </head>
  <body>
    <div class="box">
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
    </div>
  </body>
</html>

3.3.flex-flow

这个属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap

.box {
  flex-flow: <flex-direction> || <flex-wrap>;
}
.box {
  display: flex;
  width: 200px;
  flex-direction: row;
  flex-wrap: wrap-reverse;
}

缩写

.box {
  display: flex;
  width: 200px;
  flex-flow: row wrap-reverse
}

3. justify-content属性

这个属性定义了项目在主轴上的对齐方式。


.box {
  justify-content: flex-start | flex-end | center | space-between | space-around;
}
flex-start(默认值):左对齐
flex-end:右对齐
center: 居中
space-between:两端对齐,项目之间的间隔都相等。
space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。

实例:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .box {
        display: flex;
        flex-direction: row;
        flex-wrap: wrap-reverse;
        justify-content: space-around;
      }
      .box div {
        width: 100px;
        height: 100px;
        text-align: center;
        line-height: 100px;
        font-size: 20px;
      }
      .box div:nth-of-type(1) {
        background-color: red;
      }
      .box div:nth-of-type(2) {
        background-color: green;
      }
      .box div:nth-of-type(3) {
        background-color: blueviolet;
      }
      .box div:nth-of-type(4) {
        background-color: blue;
      }
    </style>
  </head>
  <body>
    <div class="box">
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
    </div>
  </body>
</html>

3.5.align-items属性

这个属性定义项目在交叉轴上如何对齐。

.box {
  align-items: flex-start | flex-end | center | baseline | stretch;
}
flex-start:交叉轴的起点对齐。
flex-end:交叉轴的终点对齐。
center:交叉轴的中点对齐。
baseline: 项目的第一行文字的基线对齐。
stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。

实例:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .box {
        display: flex;
        flex-direction: row;
        /* flex-wrap: wrap-reverse; */
        justify-content: space-around;
        align-items: baseline;
        height: 100vh;
        border: 1px solid;
      }
      .box div {
        width: 100px;
        height: 100px;
        text-align: center;
        line-height: 100px;
        font-size: 20px;
      }
      .box div:nth-of-type(1) {
        background-color: red;
      }
      .box div:nth-of-type(2) {
        background-color: green;
      }
      .box div:nth-of-type(3) {
        background-color: blueviolet;
      }
      .box div:nth-of-type(4) {
        background-color: blue;
      }
    </style>
  </head>
  <body>
    <div class="box">
      <div>1</div>
      <div style="font-size: 100px;">2</div>
      <div>3</div>
      <div>4</div>
    </div>
  </body>
</html>

3.6.align-content属性

这个属性定义了多根轴线的对齐方式。

.box {
  align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}
flex-start:与交叉轴的起点对齐。
flex-end:与交叉轴的终点对齐。
center:与交叉轴的中点对齐。
space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。
space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
stretch(默认值):轴线占满整个交叉轴。

实例:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .box {
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;
        width: 500px;
        height: 100vh;
        border: 1px solid;
        align-content: space-around;
      }
      .box div {
        width: 100px;
        height: 100px;
        text-align: center;
        line-height: 100px;
        font-size: 20px;
      }
      .box div:nth-of-type(1) {
        background-color: red;
      }
      .box div:nth-of-type(2) {
        background-color: green;
      }
      .box div:nth-of-type(3) {
        background-color: blueviolet;
      }
      .box div:nth-of-type(4) {
        background-color: blue;
      }
      .box div:nth-of-type(5) {
        background-color: red;
      }
      .box div:nth-of-type(6) {
        background-color: green;
      }
      .box div:nth-of-type(7) {
        background-color: blueviolet;
      }
      .box div:nth-of-type(8) {
        background-color: blue;
      }
    </style>
  </head>
  <body>
    <div class="box">
      <div>1</div>
      <div style="font-size: 100px;">2</div>
      <div>3</div>
      <div>4</div>
      <div>1</div>
      <div style="font-size: 100px;">2</div>
      <div>3</div>
      <div>4</div>
    </div>
  </body>
</html>

4.项目相关属性

项目常用属性

order  定义项目的排列顺序
flex-grow 定义项目的放大比例
flex-shrink 定义了项目的缩小比例
flex-basis 定义了在分配多余空间之前,项目占据的主轴空间(main size
flex  这个属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto
align-self 允许单个项目有与其他项目不一样的对齐方式

4.1.order属性

这个属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。

.item {
  order: <integer>;
}

实例:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .box {
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;
        width: 500px;
        height: 100vh;
        border: 1px solid;
        align-content: space-around;
      }
      .box div {
        width: 100px;
        height: 100px;
        text-align: center;
        line-height: 100px;
        font-size: 20px;
      }
      .box div:nth-of-type(1) {
        background-color: red;
        order: 3;
      }
      .box div:nth-of-type(2) {
        background-color: green;
        order: 2;
      }
      .box div:nth-of-type(3) {
        background-color: blueviolet;
        order: 4;
      }
      .box div:nth-of-type(4) {
        background-color: blue;
        order: 1;
      }
    </style>
  </head>
  <body>
    <div class="box">
      <div>1</div>
      <div style="font-size: 100px;">2</div>
      <div>3</div>
      <div>4</div>
    </div>
  </body>
</html>

4.2.flex-grow属性

这个属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。通俗的说,这个属性是用来定义剩余空间的分配比例的

.item {
  flex-grow: <number>; /* default 0 */
}

实例:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .box {
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;
        width: 500px;
        height: 100vh;
        border: 1px solid;
        align-content: space-around;
      }
      .box div {
        width: 100px;
        height: 100px;
        text-align: center;
        line-height: 100px;
        font-size: 20px;
      }
      .box div:nth-of-type(1) {
        background-color: red;
        flex-grow: 1;
      }
      .box div:nth-of-type(2) {
        background-color: green;
        flex-grow: 2;
      }
      .box div:nth-of-type(3) {
        background-color: blueviolet;
        flex-grow: 1;
      }
      .box div:nth-of-type(4) {
        background-color: blue;
        flex-grow: 1;
      }
    </style>
  </head>
  <body>
    <div class="box">
      <div>1</div>
      <div style="font-size: 100px;">2</div>
      <div>3</div>
      <div>4</div>
    </div>
  </body>
</html>

注意:

1.剩余空间怎么算?

上面实例中,总宽度500,每个div的宽度100,一共有4个,因此剩余空间为100

2.知道剩余空间后,如何去分配这些剩余空间?举个例子,四个div的flex-grow值分别为:

div1: 1
div2: 2
div3: 1
div4: 1

这意味着,剩余空间要分成5份,每份为100/5=20, div2占了2份,应该分40

所以最终各个div的宽度分别为

div1: 100+ 20
div2: 100 + 20*2
div3: 100 + 20
div4: 100 + 20

4.3.flex-shrink属性

这个定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小

.item {
  flex-shrink: <number>; /* default 1 */
}

实例:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .box {
        display: flex;
        flex-direction: row;
        width: 300px;
        height: 100vh;
        border: 1px solid;
        align-content: space-around;
      }
      .box div {
        width: 100px;
        height: 100px;
        text-align: center;
        line-height: 100px;
        font-size: 20px;
      }
      .box div:nth-of-type(1) {
        background-color: red;
        flex-shrink: 1;
      }
      .box div:nth-of-type(2) {
        background-color: green;
        flex-shrink: 2;
      }
      .box div:nth-of-type(3) {
        background-color: blueviolet;
        flex-shrink: 1;
      }
      .box div:nth-of-type(4) {
        background-color: blue;
        flex-shrink: 1;
      }
    </style>
  </head>
  <body>
    <div class="box">
      <div>1</div>
      <div style="font-size: 100px;">2</div>
      <div>3</div>
      <div>4</div>
    </div>
  </body>
</html>

注意:压缩后的div宽度计算方法

1.溢出空间不足怎么算?

上面实例中,总宽度300,每个div的宽度100,一共有4个,因此剩余空间为400-300,意味着总宽度还差100才能装下四个div

溢出空间 =  400 - 300 = 100

2.计算总权重

下面是每个div的shrink值

div1: 1
div2: 2
div3: 1
div4: 1

总权重 = 100(div的宽度)* 1(shrink值)+ 100 * 2 + 100 * 1 + 100 * 1 =  500

3.计算每个div的压缩比率

公式: 宽度 * shrink值 / 总权重

div1: 100 * 1 / 500 
div2: 100* 2 / 500
div3: 100* 1/ 500
div4: 100 * 1/ 500

4.计算压缩后的div宽度

公式: 原来宽度 -  溢出空间 * 压缩比率

div1: 100(原来宽度) -  100(溢出空间)*  100*1/500  = 80
div2: 100(原来宽度) -  100(溢出空间)*  100*2/500  = 60
div3: 100(原来宽度) -  100(溢出空间)*  100*1/500  = 80
div4: 100(原来宽度) -  100(溢出空间)*  100*1/500  = 80

4.4.flex-basis属性

flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。


.item {
  flex-basis: <length> | auto; /* default auto */
}

注意:这个属性的值比width优先级高

4.5.flex属性

属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。

.item {
  flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}

该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。

建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。

4.6.align-self属性

align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。

.item {
  align-self: auto | flex-start | flex-end | center | baseline | stretch;
}

5.练习

写一个flex速查demo