# Flex 弹性布局从入门到实践

TIP

传统的浮动+定位布局兼容性好,但布局繁琐,在移动端应用起来相对麻烦。而我们今天要学习的 Flex 弹性布局,操作方便,布局极为简单,在移动端应用很广泛。

当然,他的应用不仅限于移动,PC 端同样适用。

# 一、Flex 布局的基本概念

TIP

接下来让我们一起来学习 Flex 弹性布局,首先我们来了解下 lex 布局相关的一些基本概念

  • 什么是 Flex 布局
  • 什么是 Flex 容器(Flex container) 和 Flex 项目(Flex item
  • 什么是主轴,什么是交叉轴
  • Flex 项目的默认表现形式

# 1、什么是 Flex 布局

TIP

  • FlexFlexible Box的缩写,意为“弹性盒子”。

  • Flex布局是一种一维的布局模型,它给flexbox子元素之间提供了强大的空间分布和对齐能力

  • 我们说flexbox 是一种一维的布局,是因为一个flexbox一次只能处理一个维度上的元素布局,一行或者一列

# 2、什么是 Flex 容器(Flex container)和 Flex 项目(Flex item)

TIP

  • 采用Flex 布局的元素,称为 Flex 容器flex container),简称“容器”。
  • 它的所有直接子元素自动成为容器成员,称为 Flex 项目flex item),简称“项目”。
    • 通过给元素添加display:flex;display:inline-flex;来指定元素为 Flex 布局容器
      • display:flex; 弹性布局,元素自身以块级元素显示
      • display:inline-flex; 弹性布局,元素自身以行内块元素呈现
  • 任何一个元素都可以指定为 Flex 布局
  • Flex 布局,项目(子元素)的floatclearvertical-align属性将失效。

以下代码中 .flex-container盒子为 Flex 容器 ,里面的子元素.flex-item为 Flex 项目

<style>
  .flex-container {
    /* 布局方式:弹性布局 ,元素自身以块级元素显示 */
    display: flex;
    /* 布局方式:弹性布局,元素自身以行内块元素呈现 */
    display: inline-flex;
  }
</style>
<body>
  <div class="flex-container">
    <div class="flex-item">1</div>
    <div class="flex-item">2</div>
    <div class="flex-item">3</div>
    <div class="flex-item">4</div>
  </div>
</body>
inline-flex flex
image-20220805221516033 image-20220805221431013

# 3、什么是主轴,什么是交叉轴

TIP

  • Flex 容器默认存在两根轴:水平的主轴(main axis)和 垂直的交叉轴(cross axis)
  • 主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫做main end
  • 交叉轴的开始位置叫做cross start,结束位置叫做cross end
  • Flex 项目默认沿主轴排列,(即 Flex 项目默认从左往右沿水平排列)。
  • 单个Flex 项目占据的主轴空间叫做main size(主轴尺寸),占据的交叉轴空间叫做cross size(交叉尺寸)

bg2015071004

# 4、Flex 项目的默认表现形式

TIP

当 flex 容器和 flex 项目没有添加任何Flex 容器Flex 项目相关属性时,flex 项目默认的表现形式如下:

  • 子元素(项目)排列为一行 (flex-direction 属性的初始值是 row)。
  • 子元素(项目)从主轴的起始线开始排列
  • 子元素(项目)不会在主维度方向拉伸(放的下,不会拉伸),但放不下,会缩小
  • 子元素(项目)没有设置高度时,被拉伸来填充交叉轴大小(单行时项目的高度等于容器高)
  • flex-basis 属性为 auto(即元素的宽为自动)
  • flex-wrap 属性为 nowrap(子项默认放不下时,不会换行)

代码演示

<style>
  .flex-container {
    padding: 10px;
    width: 200px;
    height: 200px;
    background-color: skyblue;
    /* 弹性布局 */
    display: flex;
  }
  .flex-item {
    /* 未设置高度 */
    width: 100px;
    line-height: 50px;
    font-size: 30px;
    color: #fff;
    text-align: center;
    background-color: tomato;
    margin: 5px;
  }
</style>
<body>
  <div class="flex-container">
    <div class="flex-item">1</div>
    <div class="flex-item">2</div>
    <div class="flex-item">3</div>
    <div class="flex-item">4</div>
  </div>
</body>

image-20220805225626873

注:

  • .flex-item的宽为 100px,4 个加起来 400px,超过了.flex-container宽度,但元素并没换行,而是自动压缩到容器中显示。
  • .flex-item没有设置高度时,其高度会被拉伸与父容器.flex-container的高一样大小。

# 二、Flex 容器属性

接下来我们来学习 Flex 容器相关的属性,以下 6 个属性都是设置在Flex 容器

属性名 说明
flex-direction 设置主轴的方向
flex-wrap 设置(项目)子元素是否换行
flex-flow 复合属性,相当于同时设置了 flex-direction 和 flex-wrap
justify-content 设置主轴上的(项目)子元素排列方式
align-items 设置交叉轴上的(项目)子元素排列方式 (单行)
align-content 设置多轴线在交叉轴上排列方式 (多行)

# 1、flex-direction 设置主轴方向

TIP

flex-direction 属性决定了 Flex 容器的主轴方向,即 Flex 项目的排列方向

  • 默认主轴方向就是 x 轴,水平向右
  • 默认交叉轴就是 y 轴,垂直向下

语法

/* 主轴为行(x轴),水平向右 */
flex-direction: row;

flex-direction 属性的 4 个值

属性值 说明
row (默认值)主轴为水平方向,起点在左端。(即:交叉轴在垂直方向,起点在上边框位置
row-reverse 主轴为水平方向,起点在右端。(即:交叉轴在垂直方向,起点在元素上边框位置)
column 主轴为垂直方向,起点元素上边框位置。(即:交叉轴为水平方向,起点在左端)
column-reverse 主轴为垂直方向,起点在下沿。 (即:交叉轴为水平方向,起点在左端 )

案例演示:

<style>
  .flex-container {
    /* 布局方式:弹性布局,元素自身以行内块元素呈现 */
    display: inline-flex;
    /* 定义主轴方向,可选值:row、row-reverse、column、column-reverse */
    flex-direction: row;
    padding: 10px;
    background-color: skyblue;
  }
  .flex-item {
    width: 50px;
    height: 50px;
    line-height: 50px;
    font-size: 30px;
    color: #fff;
    text-align: center;
    background-color: tomato;
    margin: 10px;
  }
</style>
<body>
  <div class="flex-container">
    <div class="flex-item">1</div>
    <div class="flex-item">2</div>
    <div class="flex-item">3</div>
  </div>
</body>

flex-direction 属性,不同值的表现效果如下:

row row-reverse column column-reverse
image-20220805223910977 image-20220805223932050 image-20220805223956822 image-20220805224016199

# 2、flex-wrap 项目如何换行

TIP

  • 默认情况下,项目都排在一条线(又称 "轴线" )上排列。
  • flex-wrap属性定义,如果项目在一条轴线(主轴)排不下时,如何换行。

语法

/* 放不下时,不换行 */
flex-wrap: nowrap;

flex-wrap 属性的 3 个值

属性值 说明
nowrap (默认):不换行
wrap 换行,第一行在上方 (或第一列左边)
wrap-reverse 换行,第一行在下方(或第一列在右边)
<style>
  .flex-container {
    /* 弹性布局 */
    display: flex;
    /* 主轴为垂直方向 */
    /* flex-direction: column; */
    /* 项目在放不下时,如何换行  wrap nowrap wrap-reverse */
    flex-wrap: wrap;
    width: 200px;
    height: 200px;
    padding: 10px;
    background-color: skyblue;
  }
  .flex-item {
    width: 50px;
    line-height: 50px;
    font-size: 30px;
    color: #fff;
    text-align: center;
    background-color: tomato;
    margin: 5px;
  }
</style>
<body>
  <div class="flex-container">
    <div class="flex-item">1</div>
    <div class="flex-item">2</div>
    <div class="flex-item">3</div>
    <div class="flex-item">4</div>
    <div class="flex-item">5</div>
  </div>
</body>

主轴为 row,水平方向时

nowrap wrap wrap-reverse
image-20220822151546824 image-20220822151331254 image-20220822151639155

主轴为 column,垂直方向时

nowrap wrap wrap-reverse
image-20220822151806568 image-20220822151827864 image-20220822151844628

# 3、flex-flow 主轴方向和项目如何换行

TIP

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

语法:

flex-flow: row nowrap;
<style>
  .flex-container {
    width: 100px;
    height: 200px;
    padding: 10px;
    background-color: skyblue;
    /* 弹性布局 */
    display: flex;
    /* flex-wrap  主轴方向和项目如何换行 */
    flex-flow: column wrap;
  }
  .flex-item {
    line-height: 50px;
    font-size: 30px;
    color: #fff;
    text-align: center;
    background-color: tomato;
    margin: 5px;
    padding: 5px 10px;
  }
</style>
<body>
  <div class="flex-container">
    <div class="flex-item">1</div>
    <div class="flex-item">2</div>
    <div class="flex-item">3</div>
    <div class="flex-item">4</div>
    <div class="flex-item">5</div>
  </div>
</body>
row nowrap row wrap column nowrap column wrap
image-20220805233433320 image-20220805233548713 image-20220805233609812 image-20220805233653157

# 4、justify-content 项目在主轴上对齐方式

TIP

justify-content属性定义了项目在主轴上的对齐方式

/* 项目在主轴上左对齐 */
justify-content: flex-start;

justify-content 属性的 5 个值

属性值 说明
flex-start (默认值)左对齐
flex-end 右对齐
center 居中
space-between 两端对齐,项目之间的间隔都相等
space-around 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。
space-evenly 使每个元素之间和元素距离边距的距离都相等,但iphone 的 SE 上不支持,会失效,基本不用
<style>
  .flex-container {
    padding: 10px;
    background-color: skyblue;
    /* 弹性布局 */
    display: flex;
    /* 项目在主轴上的对齐方式 */
    justify-content: center;
  }
  .flex-item {
    width: 50px;
    line-height: 50px;
    font-size: 30px;
    color: #fff;
    text-align: center;
    background-color: tomato;
    margin: 5px;
  }
</style>
<body>
  <div class="flex-container">
    <div class="flex-item">1</div>
    <div class="flex-item">2</div>
    <div class="flex-item">3</div>
    <div class="flex-item">4</div>
  </div>
</body>
flex-start flex-end center
image-20220805230729077 image-20220805230801833 image-20220805230852435
space-between space-around space-evenly
image-20220805231029364 image-20220805230944796 image-20220805231057111

# 5、align-items 项目在交叉轴上对齐方式

TIP

align-items属性定义项目在交叉轴上如何对齐,只对单行有效

/* 默认值,项目未设置高度或设为auto,将占满整个容器的高度 */
align-items: stretch;

align-item 属性的 5 个值

属性值 说明
stretch (默认值):如果项目未设置高度或设为 auto,将占满整个容器的高度。
flex-start 交叉轴的起点对齐
flex-end 交叉轴的终点对齐
center 交叉轴的中点对齐
baseline 所有元素向基线对齐。侧轴起点到元素基线距离最大的元素将会于侧轴起点对齐以确定基线。

注意:

align-items的值不是stretch时,其项目未设置高时,其高为内容大小,并不会拉伸到容器高度。

<style>
  .flex-container {
    height: 200px;
    background-color: skyblue;
    /* 弹性布局 */
    display: flex;
    /* 项目在交叉轴上如何对齐 */
    align-items: baseline;
  }
  .flex-item {
    width: 50px;
    line-height: 50px;
    font-size: 30px;
    color: #fff;
    text-align: center;
    background-color: tomato;
    padding: 5px 10px;
    margin: 0 5px;
  }
  .flex-item:nth-child(1) {
    height: 50px;
    font-size: 14px;
  }
  .flex-item:nth-child(2) {
    height: 100px;
    font-size: 40px;
  }
</style>
<body>
  <div class="flex-container">
    <div class="flex-item">1</div>
    <div class="flex-item">2</div>
    <div class="flex-item">3</div>
  </div>
</body>
stretch flex-start flex-end
image-20220806000739309 image-20220806000642919 image-20220806000707532
center baseline
image-20220806000803292 image-20220806001023139

当主轴放不下,允许换行时,align-items 的效果

  • 当项目放不下,换行时,可以把每一行看作一个新的 flex 容器
  • align-items控制项目在这个新容器的交叉轴上的对齐方式
  • 每一行容器占的高度 = 当前行最高元素的高 +(容器高 - 每一行最高元素的高) / 行数

案例

<style>
  .flex-container {
    width: 300px;
    height: 300px;
    background-color: skyblue;
    /* 弹性布局 */
    display: flex;
    /* 项目在交叉轴上如何对齐 */
    align-items: baseline;
    /* 放不下换行 */
    flex-wrap: wrap;
  }
  .flex-item {
    width: 50px;
    line-height: 50px;
    font-size: 30px;
    color: #fff;
    text-align: center;
    background-color: tomato;
    padding: 5px 10px;
    margin: 0px 5px;
  }
  .flex-item:nth-child(2) {
    height: 100px;
  }
</style>
<body>
  <div class="flex-container">
    <div class="flex-item">1</div>
    <div class="flex-item">2</div>
    <div class="flex-item">3</div>
    <div class="flex-item">4</div>
    <div class="flex-item">5</div>
    <div class="flex-item">6</div>
  </div>
</body>
stretch flex-start flex-end
image-20220809004313166 image-20220809004130058 image-20220809004336681
center baseline
image-20220809004412674 image-20220809004908246

# 6、align-content 多根轴线对齐方式(多行)

TIP

  • align-content属性定义了多根轴线在(交叉轴上的)对齐方式。
  • 如果项目只有一根轴线,该属性不起作用。
/* 多行在交叉轴上居中对齐 */
align-content: center;

align-content 属性的 6 个值

属性值 说明
stretch (默认值)轴线占满整个交叉轴
flex-start 与交叉轴的起点对齐
flex-end 与交叉轴的终点对齐
center 与交叉轴的中点对齐
space-between 与交叉轴两端对齐,轴线之间的间隔平均分布
space-around 每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
<style>
  .flex-container {
    height: 300px;
    width: 300px;
    background-color: skyblue;
    /* 弹性布局 */
    display: flex;
    /* 项目放不下自动换行 */
    flex-wrap: wrap;
    /* 多轴线在交叉轴上的对齐方式 */
    align-content: space-around;
  }
  .flex-item {
    width: 50px;
    line-height: 50px;
    font-size: 30px;
    color: #fff;
    text-align: center;
    background-color: tomato;
    padding: 5px 10px;
    margin: 5px;
  }
  .flex-item:nth-child(1) {
    height: 50px;
  }
  .flex-item:nth-child(2) {
    height: 100px;
  }
</style>
<body>
  <div class="flex-container">
    <div class="flex-item">1</div>
    <div class="flex-item">2</div>
    <div class="flex-item">3</div>
    <div class="flex-item">4</div>
    <div class="flex-item">5</div>
    <div class="flex-item">6</div>
  </div>
</body>
flex-start flex-end center
image-20220806003454151 image-20220806003522996 image-20220806003547688
stretch space-between space-around
image-20220806003606314 image-20220806003630872 image-20220806003654446

# 三、Flex 项目属性

TIP

以下 6 大属性为 Flex 项目属性,都是直接添加到项目身上。

属性名 说明
order 属性定义项目的排列顺序。数值越小,排列越靠前,默认为 0
align-self 单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性
默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch
flex-grow flex 项 主尺寸 的 flex 增长系数。默认为0,即如果存在剩余空间,也不放大。
flex-shrink flex 项主尺寸的缩小比例,默认为1,即如果空间不足,该项目将缩小。
flex-basis 定义了在分配多余空间之前,项目占据的主轴空间(main size
flex flex属性是flex-grow, flex-shrinkflex-basis的简写
默认值为0 1 auto。后两个属性可选。

# 1、order 项目的排列顺序

TIP

  • order属性定义项目的排列顺序。
  • order属性值为>0的整数,数值越小,排列越靠前,默认为 0。

语法

order: 1;
<style>
  .flex-container {
    height: 100px;
    background-color: skyblue;
    /* 弹性布局 */
    display: flex;
  }
  .flex-item {
    width: 50px;
    line-height: 50px;
    font-size: 30px;
    color: #fff;
    text-align: center;
    background-color: tomato;
    padding: 5px 10px;
    margin: 5px;
  }
  .flex-item:nth-child(1) {
    /* 排列顺序,数值越小,越排前 */
    order: 1;
  }
  .flex-item:nth-child(2) {
    /* 排列顺序,数值越小,越排前 */
    order: 3;
  }
</style>
<body>
  <div class="flex-container">
    <div class="flex-item">1</div>
    <div class="flex-item">2</div>
    <div class="flex-item">3</div>
    <div class="flex-item">4</div>
  </div>
</body>

image-20220806150515031

# 2、align-self 单个项目交叉轴对齐方式

TIP

  • align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。
  • align-self的默认值为auto,表示继承父元素的align-items属性
  • 如果父元素没有设置align-items属性,则等同于stretch(要生效,元素自身没有设置高度)。
/* 与交叉轴起点对齐 */
align-self: flex-start;

align-self 属性的 6 个值

该属性的 6 个值,除了 auto,其他都与 align-items 的属性完全一致

属性值 说明
auto 默认值
表示继承父元素的align-items属性,如果没有父元素,则等同于stretch
stretch 如果项目未设置高度或设为auto,将占满整个容器的高度。
flex-start 交叉轴的起点对齐
flex-end 交叉轴的终点对齐
center 交叉轴的中点对齐
baseline 项目的第一行文字的基线对齐
<style>
  .flex-container {
    height: 200px;
    background-color: skyblue;
    /* 弹性布局 */
    display: flex;
    align-items: center;
  }
  .flex-item {
    line-height: 50px;
    font-size: 30px;
    color: #fff;
    text-align: center;
    background-color: tomato;
    padding: 5px 10px;
    margin: 5px;
  }
  .flex-item:nth-child(1) {
    align-self: auto;
  }
  .flex-item:nth-child(2) {
    align-self: stretch;
  }
  .flex-item:nth-child(3) {
    align-self: flex-start;
  }
  .flex-item:nth-child(4) {
    align-self: flex-end;
  }
  .flex-item:nth-child(5) {
    align-self: center;
  }
  .flex-item:nth-child(6) {
    align-self: baseline;
  }
</style>
<body>
  <div class="flex-container">
    <div class="flex-item">auto</div>
    <div class="flex-item">stretch</div>
    <div class="flex-item">flex-start</div>
    <div class="flex-item">flex-end</div>
    <div class="flex-item">center</div>
    <div class="flex-item">baseline</div>
  </div>
</body>

image-20220806152200078

注意:

当项目换行时,其align-self单个项目对齐方式,是相对于其所在的那一行的轴线而言。

<style>
  .flex-container {
    height: 400px;
    width: 600px;
    background-color: skyblue;
    /* 弹性布局 */
    display: flex;
    /* 允许换行 */
    flex-wrap: wrap;
    /* 项目在交叉轴,垂直方向上对齐方式 */
    align-items: center;
  }
  .flex-item {
    line-height: 50px;
    font-size: 30px;
    color: #fff;
    text-align: center;
    background-color: tomato;
    padding: 5px 10px;
    margin: 5px;
  }
  .flex-item:nth-child(1) {
    /* 单独设置了高为100px */
    height: 100px;
    align-self: auto;
  }
  .flex-item:nth-child(2) {
    align-self: stretch;
  }
  .flex-item:nth-child(3) {
    align-self: flex-start;
  }
  .flex-item:nth-child(4) {
    align-self: flex-end;
  }
  .flex-item:nth-child(5) {
    align-self: center;
  }
  .flex-item:nth-child(6) {
    align-self: baseline;
  }
</style>
<body>
  <div class="flex-container">
    <div class="flex-item">auto</div>
    <div class="flex-item">stretch</div>
    <div class="flex-item">flex-start</div>
    <div class="flex-item">flex-end</div>
    <div class="flex-item">center</div>
    <div class="flex-item">baseline</div>
  </div>
</body>

image-20220806152829565

# 3、flex-grow 项目主轴放大系数

TIP

  • flex-grow 设置 flex 项目 主尺寸(main size) 的 flex 增长系数
  • 主尺寸是项目的宽度或高度,这取决于flex-direction
  • flex-grow 属性,在 Flex 容器有剩余空间时生效(默认主轴为水平轴)

剩余空间 = flex 容器宽大小 - 所有 flex 项目宽加起来的大小

注:剩余空间的值一定要是大于 0 的

  • flex-grow 的默认值为 0,表示及时有剩余空间,也不增长(放大)
  • flex-grow 的值为>=0 的数字。

# (1)项目放大后尺寸计算公式

TIP

  • 当所有项目的 flex-grow 值的总和加起来 < 1

    项目放大后宽 = 项目原始宽 + 剩余空间 * 项目的 flex-grow 值

  • 当所有项目的 flex-grow 值的总和加起来 >= 1

    项目放大后宽 = 项目原始宽 + 剩余空间 * (flex-grow 值) / 所有项目的 flex-grow 值总和

案例 1

flex 容器存在剩余空间,且所有flex-grow值总和 < 1

<style>
  .flex-container {
    width: 400px;
    height: 100px;
    background-color: skyblue;
    /* 弹性布局 */
    display: flex;
    flex-wrap: wrap;
    align-items: center;
  }
  .flex-item {
    width: 50px;
    line-height: 50px;
    font-size: 30px;
    color: #fff;
    text-align: center;
  }
  .flex-item:nth-child(1) {
    flex-grow: 0.1;
    background-color: tomato;
  }
  .flex-item:nth-child(2) {
    flex-grow: 0.2;
    background-color: khaki;
  }
  .flex-item:nth-child(3) {
    flex-grow: 0.3;
    background-color: pink;
  }
</style>
<body>
  <div class="flex-container">
    <div class="flex-item">1</div>
    <div class="flex-item">2</div>
    <div class="flex-item">3</div>
  </div>
</body>

image-20220809010011069

案例 2

flex 容器存在剩余空间,且所有flex-grow值总和 >= 1

<style>
  .flex-container {
    width: 400px;
    height: 100px;
    background-color: skyblue;
    /* 弹性布局 */
    display: flex;
    flex-wrap: wrap;
    align-items: center;
  }
  .flex-item {
    width: 50px;
    line-height: 50px;
    font-size: 30px;
    color: #fff;
    text-align: center;
  }
  .flex-item:nth-child(1) {
    flex-grow: 1;
    background-color: tomato;
  }
  .flex-item:nth-child(2) {
    flex-grow: 2;
    background-color: khaki;
  }
  .flex-item:nth-child(3) {
    flex-grow: 3;
    background-color: pink;
  }
</style>
<body>
  <div class="flex-container">
    <div class="flex-item">1</div>
    <div class="flex-item">2</div>
    <div class="flex-item">3</div>
  </div>
</body>
image-20220806160342883 image-20220806160003081

温馨提示:

flex 容器的剩余空间为 0 时,不管 flex 项目的flex-grow的值是多少,flex 项都不会放大

# 4、flex-shrink 项目主轴上缩放系数

TIP

  • flex-shrink属性指定了 flex 元素的收缩规则。
  • 当所有flex项目宽度之和大于容器的时候才会发生收缩(默认主轴为水平方向)
  • flex 项目收缩的大小是依据所有 flex 项的flex-shrink的值决定的。
  • flex-shrink的默认值为1,表示容器空间不足时,所有项目等比缩小
  • 只有当 flex 容器设置了flex-wrap: nowrap;时,才能看到效果

# (1)flex 项目收缩后尺寸大小计算

当 flex-shrink 所有值总和 < 1 时

  • 第一步:计算溢出宽 = 所有项目宽 - 容器宽
  • 第二步:所有子项的总缩放宽 = 溢出宽 * 所有项目flex-shrink值之和
  • 第三步:当前项目缩放比例 =(项目原始宽 * flex-shrink 值)/ 每个项目宽 * flex-shrink 值 之和)
  • 第四步:项目收缩宽 = 所有子项的总缩放宽 * 当前缩放项的比例
  • 第五步:项目收缩后宽 = 项目原始宽 - 项目收缩宽
<style>
  .flex-container {
    width: 400px;
    height: 100px;
    background-color: skyblue;
    /* 弹性布局 */
    display: flex;
    align-items: center;
    float: left;
  }
  .flex-item {
    width: 50px;
    line-height: 50px;
    font-size: 30px;
    color: #fff;
    text-align: center;
  }
  .flex-item:nth-child(1) {
    background-color: tomato;
    width: 300px;
    flex-shrink: 0.1;
  }
  .flex-item:nth-child(2) {
    background-color: khaki;
    width: 200px;
    flex-shrink: 0.2;
  }
  .flex-item:nth-child(3) {
    background-color: pink;
    width: 100px;
    flex-shrink: 0.2;
  }
</style>
<body>
  <div class="flex-container">
    <div class="flex-item">1</div>
    <div class="flex-item">2</div>
    <div class="flex-item">3</div>
  </div>
</body>

image-20220806193527498

当 flex-shrink 所有值总和 >= 1 时

  • 第一步:计算溢出宽 = 所有项目宽 - 容器宽
  • 第二步:所有子项的总缩放宽 = 溢出宽
  • 第三步:当前项目缩放比例 =(项目原始宽 * flex-shrink 值)/ 每个项目宽 * flex-shrink 值 之和)
  • 第四步:项目收缩宽 = 所有子项的总缩放宽 * 当前缩放项的比例

    注:当项目的收缩宽 >项目原始宽时,此计算方式无效

  • 第五步:项目收缩后宽 = 项目原始宽 - 项目收缩宽
<style>
  .flex-container {
    width: 400px;
    height: 100px;
    background-color: skyblue;
    /* 弹性布局 */
    display: flex;
    align-items: center;
  }
  .flex-item {
    width: 50px;
    line-height: 50px;
    font-size: 30px;
    color: #fff;
    text-align: center;
  }
  .flex-item:nth-child(1) {
    background-color: tomato;
    width: 300px;
    flex-shrink: 1;
  }
  .flex-item:nth-child(2) {
    background-color: khaki;
    width: 200px;
    flex-shrink: 2;
  }
  .flex-item:nth-child(3) {
    background-color: pink;
    width: 100px;
    flex-shrink: 3;
  }
</style>
<body>
  <div class="flex-container">
    <div class="flex-item">1</div>
    <div class="flex-item">2</div>
    <div class="flex-item">3</div>
  </div>
</body>

image-20220806195619400

  • 多个 flex 项目,只有其中一个设置了 flex-shrink,且小于 1 时

主要是要考虑 flex-shrink 的默认值为 1

<style>
  .flex-container {
    width: 400px;
    height: 100px;
    background-color: skyblue;
    /* 弹性布局 */
    display: flex;
    align-items: center;
  }
  .flex-item {
    width: 50px;
    line-height: 50px;
    font-size: 30px;
    color: #fff;
    text-align: center;
  }
  .flex-item:nth-child(1) {
    background-color: tomato;
    width: 300px;
    flex-shrink: 0.5;
  }
  .flex-item:nth-child(2) {
    background-color: khaki;
    width: 200px;
  }
  .flex-item:nth-child(3) {
    background-color: pink;
    width: 100px;
  }
  /* 
    溢出宽=所有子项总宽(300+200+100) - 容器宽(400)=200
    所有项目缩放总宽=溢出宽=200
    项目1缩小后宽=300 - 300*0.5/(300*0.5+200*1+100*1)*200=300-150/450*200=233.3
    项目2缩小后宽=200 - 200*1/(300*0.5+200*1+100*1)*200=200-200/450*200=111.1
    项目1缩小后宽=100 - 100*1/(300*0.5+200*1+100*1)*200=100-100/450*200=55.5
    */
</style>
<body>
  <div class="flex-container">
    <div class="flex-item">1</div>
    <div class="flex-item">2</div>
    <div class="flex-item">3</div>
  </div>
</body>

image-20220806195213815

  • flex-shrink: 0;时,无论如何不缩放,这种情况在实际开发中的用较多
<style>
  .flex-container {
    width: 400px;
    height: 100px;
    background-color: skyblue;
    /* 弹性布局 */
    display: flex;
    align-items: center;
    float: left;
  }
  .flex-item {
    width: 50px;
    line-height: 50px;
    font-size: 30px;
    color: #fff;
    text-align: center;
  }
  .flex-item:nth-child(1) {
    background-color: tomato;
    width: 300px;
    flex-shrink: 0;
  }
  .flex-item:nth-child(2) {
    background-color: khaki;
    width: 200px;
    flex-shrink: 1;
  }
  .flex-item:nth-child(3) {
    background-color: pink;
    width: 100px;
    flex-shrink: 1;
  }
  /* 
          溢出宽=所有子项总宽(300+200+100) - 容器宽(400)=200
          所有项目缩放总宽=溢出宽=200
          项目1缩小后宽=300-0=300
          项目2缩小后宽=200 - 200*2/(300*0+200*1+100*1)*200=200-200/300*200=66.67
          项目1缩小后宽=100 - 100*3/(300*0+200*1+100*1)*200=100-100/300*200=33.3
      */
</style>
<body>
  <div class="flex-container">
    <div class="flex-item">1</div>
    <div class="flex-item">2</div>
    <div class="flex-item">3</div>
  </div>
</body>

image-20220806200424200

在实际开发中,用的最多的是以下两种情况

  • flex-shrink:0;元素无任何如何不缩放
  • 所有元素的 flex-shrink 值,默认都为 1,等比缩小。

# 5、flex-basis 分配剩余空间前,项目占据主轴空间大小(main size)

TIP

  • flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)
  • 浏览器根据这个属性,计算主轴是否有多余空间。
  • 它的默认值为auto,即项目的本来大小(如果width:200px,则缩放以200px为参考)
  • flex-basis的优先级要高于width
<style>
  .flex-container {
    width: 600px;
    height: 100px;
    background-color: skyblue;
    /* 弹性布局 */
    display: flex;
    align-items: center;
  }
  .flex-item {
    width: 50px;
    line-height: 50px;
    font-size: 30px;
    color: #fff;
    text-align: center;
  }
  .flex-item:nth-child(1) {
    background-color: tomato;
    width: 100px;
    /* 剩余空间前,元素的大小 */
    flex-basis: 200px;
    flex-grow: 1;
  }
  .flex-item:nth-child(2) {
    background-color: khaki;
    width: 200px;
    flex-grow: 2;
  }
  .flex-item:nth-child(3) {
    background-color: pink;
    width: 100px;
    flex-grow: 3;
  }
  /*
        剩余宽=600-(200+200+100)=100
        项目1放大后宽=200+ 1/6*100=216.7
        项目2放大后宽=200+ 2/6*100=233.3
        项目3放大后宽=100+ 3/6*100=150
    */
</style>
<body>
  <div class="flex-container">
    <div class="flex-item">1</div>
    <div class="flex-item">2</div>
    <div class="flex-item">3</div>
  </div>
</body>

image-20220806203658016

注意区分下面两种情况

/*  在计算剩余空间之前,元素宽为200px */
.flex-auto {
  width: 200px;
  /* 这里auto相当于200px */
  flex-basis: auto;
}
/* 在计算剩余空间之前,元素的宽为0 */
.flex-auto {
  width: 200px;
  /* 这里相当于元素宽为 0 */
  flex-basis: 0%;
}

# 6、flex 项目放大、缩小、空间占据

TIP

  • flex属性是flex-grow, flex-shrinkflex-basis的简写,默认值为0 1 auto
  • 2 个快捷值:
    • flex:auto;表示:flex:1 1 auto;
    • flex:none;表示:flex: 0 0 auto

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

  • flex:1 表示: flex:1 1 0%;
<style>
  .flex-container {
    height: 100px;
    background-color: skyblue;
    /* 弹性布局 */
    display: flex;
    /* 两端对齐 */
    justify-content: space-between;
    /* 垂直居中对齐 */
    align-items: center;
  }
  .flex-item {
    line-height: 50px;
    font-size: 30px;
    color: #fff;
    text-align: center;
  }
  .flex-item:nth-child(1) {
    background-color: tomato;
    width: 200px;
  }
  .flex-item:nth-child(2) {
    background-color: khaki;
    overflow: hidden;
    /* 文字不换行 */
    white-space: nowrap;
    /* flex:1相当于 flex:1 1 0%; */
    flex: 1;
  }
  .flex-item:nth-child(3) {
    width: 300px;
    background-color: pink;
  }
</style>
<body>
  <div class="flex-container">
    <div class="flex-item">logo</div>
    <div class="flex-item">搜索</div>
    <div class="flex-item">登录</div>
  </div>
</body>

GIF-2022-8-6-20-54-34

# 四、Flex 实战

# 1、元素水平垂直居

<style>
  .flex-container {
    width: 200px;
    height: 200px;
    background-color: skyblue;
    display: flex;
    /* 水平居中 */
    justify-content: center;
    /* 垂直居中 */
    align-items: center;
  }
  .flex-item {
    width: 100px;
    height: 100px;
    background-color: khaki;
  }
</style>
<body>
  <div class="flex-container">
    <div class="flex-item"></div>
  </div>
</body>

image-20220806211402830

# 2、画 3 色子

sssese20222

<style>
  .dice {
    width: 95px;
    height: 95px;
    border: 1px solid #666;
    border-radius: 5px;
    display: flex;
    justify-content: space-between; /*两端对齐*/
    padding: 5px;
  }
  .dice span {
    width: 20px;
    height: 20px;
    background-color: #000;
    border-radius: 50%;
  }
  /*色子2*/
  .dice span:nth-child(2) {
    align-self: center;
  }
  /*色子3*/
  .dice span:last-child {
    align-self: flex-end;
  }
</style>
<body>
  <div class="dice">
    <span></span>
    <span></span>
    <span></span>
  </div>
</body>

注:

关于 1 点色子到 6 点色子,如何用弹性布局来实现。

详细可以参考博客地址 (opens new window) 👆

# 3、双飞翼布局

TIP

左右固定,中间自适应,最中间的内容放在第一位,有利用 SEO 搜索引擎优化。

GIF-2022-8-6-21-45-29

<style>
  html,
  body {
    width: 100%;
    height: 100%;
    margin: 0;
  }
  .container {
    display: flex;
    height: 100%;
  }
  .middle {
    flex-grow: 1;
    background-color: khaki;
    order: 1;
  }
  .left {
    width: 200px;
    background-color: skyblue;
    order: 0;
  }
  .right {
    width: 200px;
    background-color: tomato;
    order: 2;
  }
</style>
<body>
  <div class="container">
    <div class="middle">中间</div>
    <div class="left">左边</div>
    <div class="right">右边</div>
  </div>
</body>

# 4、flex 怎么实现盒子 1 在最左边,2 、3 在最右边

2022-08-12

<style>
  html,
  body {
    margin: 0;
    padding: 0;
  }
  .container {
    height: 200px;
    border: 2px solid #000;
    display: flex; /*弹性布局*/
    justify-content: space-between; /*两端对齐*/
  }
  .container .left {
    width: 300px;
    background-color: tomato;
  }
  .container .right {
    display: flex; /*弹性布局,这样子元素没有添加高度时,会和父元素一样高*/
  }
  .container .right .item1 {
    width: 200px;
    background-color: pink;
  }
  .container .right .item2 {
    width: 100px;
    background-color: skyblue;
  }
</style>
<body>
  <div class="container">
    <div class="left"></div>
    <div class="right">
      <div class="item1"></div>
      <div class="item2"></div>
    </div>
  </div>
</body>

# 5、星级评估

GIF-2022-8-6-21-23-15

<style>
  .rating {
    display: flex;
    align-items: center;
    justify-content: center;
    /*从右往左排列,关键性代码*/
    flex-direction: row-reverse;
  }
  .rating-star {
    position: relative;
    margin: 0 2px;
    font-size: 42px;
    color: #ddd;
  }
  .rating-star::before {
    /*实心星*/
    content: "\2605";
    left: 0px;
    position: absolute;
  }
  /*鼠标滑动到星上时,星后面对应的星都变红*/
  .rating-star:hover:before,
  .rating-star:hover ~ .rating-star:before {
    color: red;
  }
</style>
<body>
  <div class="rating">
    <span class="rating-star"></span>
    <span class="rating-star"></span>
    <span class="rating-star"></span>
    <span class="rating-star"></span>
    <span class="rating-star"></span>
  </div>
</body>

# 6、如何解决 flex 布局 7 个元素使用 space-between 最后一行两边分布的问题?

TIP

如果我们每一行显示的个数为 n,那我们可以最后一行子项的后面加上 n-2 个 span 元素,span 元素的宽度和其它子项元素宽度一样,但不用设置高度。

为什么是添加 n-2 个 span 元素呢 ?

  • 当最后一行只有 1 个子元素时,他会默认靠左,不用处理
  • 当最后一行子元素正好时,我们就不用关心这个问题。

所以要去掉这两种情况,只需要加 n-2 个 span 元素就好

案例演示:在没有加 n-2 个 span 元素前的效果

<style>
  .container {
    width: 500px;
    display: flex; /*弹性布局*/
    justify-content: space-between; /*两端对齐*/
    flex-wrap: wrap; /*超出部分换行*/
  }
  .item {
    width: 120px;
    height: 100px;
    background-color: pink;
    margin-top: 10px;
  }
</style>
<body>
  <div class="container">
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
    <div class="item">4</div>
    <div class="item">5</div>
    <div class="item">6</div>
    <div class="item">7</div>
  </div>
</body>

2022-808922

添加了 n-2个 span 元素后效果(这里每行 4 个,4-2=2,所以只需要加 2 个 span 就可以了)如下所示:

<style>
  .container span {
    width: 120px;
  } /*span宽和子项宽一样*/
</style>
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <span></span>
  <span></span>
</div>

2022-098022

注:

如果想非常熟练的掌握 Flex 弹性布局,可以去博客看 102 个常见的布局案例,这 102 个常见的布局案例部都是采用最新 Flex 布局技术来实现的。

点击查看,102 个常见的 Flex 布局最佳实践 (opens new window) 👆

image-20220806212603629

接下来的移动端的项目开发,我们就会采用最新的 Flex 布局来实现整站的页面开发。

# 五、专项案例训练(作业)

根据课程进度完成以下针对性案例开发,开发过程要求:

  • 利用 PS(Photoshop)与 PxCook 结合,在 PS 中的找到 PxCook-切图面板,选中想要切图的图层 或者 图层组 ,然后点击切图面板上的 标记为切图 按钮 -> 再导出到 PxCook
  • 在 PxCook 中下载对应的切图素材即可获取当前案例中的开发素材
  • 开发过程中所需的尺寸在 PxCook 中量取

以上开发开发流程是用于个人训练从切图、量取尺寸,到具体的开发过程,包括平时自学中如果没有 PSD 源文件时,PxCook 是最佳的个人开发工具。因此现在阶段推荐使用这种方式来练习

在实际企业网页开发中(更多是团队协作开发,流程如下)

  • 设计师设计好 UI 设计稿后 -> 会在 PS 中标记切图 -> 导出至蓝湖(国内企业用的多)中
  • 前端开发人员下载网页开发所需的素材 -> 在蓝湖中量取尺寸 -> 即可开发静态页面

我们把 CSS/CSS3 基础知识全部学习完之后,会有 3 大项目开发(PC 端,响应式,移动端)会按照企业真实团队协作的方式,用 3 个项目来完整的实践。

PSD 的源文件设计稿(联系助理老师获取即可)

  • 具体操作步骤讲解,在钉钉群直播回放视频(第十二课:CSS 盒子模型)中可查阅

切记

学习阶段一定要按照以上的流程学习,提前熟悉工具和整个开发步骤,企业真实项目开发就是这样的流程

# 1、Flex 开发酷狗音乐播放列表

Flex开发酷狗音乐播放列表

点击查看完整版视频讲解

# 2、Flex 弹性布局(开发今日头条热门视频布局效果)

Flex弹性布局(开发今日头条热门视频布局效果)

点击查看完整版视频讲解

# 3、Flex 弹性布局(开发微博热搜榜效果)

Flex弹性布局(开发微博热搜榜效果)

点击查看完整版视频讲解
上次更新时间: 9/22/2023, 7:57:09 PM

大厂最新技术学习分享群

大厂最新技术学习分享群

微信扫一扫进群,获取资料

X