前端-CSS学习笔记10-Flex布局

资料来源 css-tricks.com

1. 原先布局的痛点

  • 布局的传统解决方案,基于盒状模型,依赖 display 属性 + position属性 + float属性

  • 对于那些特殊布局非常不方便

    • 比如在父内容里面垂直居中一个块内容
    • 比如使容器的所有子项等分可用宽度/高度,而不管有多少宽度/高度可用
    • 比如使多列布局中的所有列采用相同的高度,即使它们包含的内容量不同
  • 所以长久以来,非常期待一种真正可以用于对元素布局的方案

    • 2009年,W3C 提出了Flex 布局,可以简便、完整、响应式地实现各种页面布局

2. 认识flexbox

  • Flexbox翻译为弹性盒子

    • 弹性盒子是一种用于按行或按列布局元素的一维布局方法
    • 元素可以膨胀以填充额外的空间, 收缩以适应更小的空间
    • 通常使用Flexbox来进行布局的方案称之为flex布局(flex layout)
    • 任何一个容器都可以指定为 Flex 布局
  • flex布局是目前web开发中使用最多的布局方案

    • flex 布局(Flexible 布局,弹性布局)
    • 目前特别在移动端可以说已经完全普及
    • 在PC端也几乎已经完全普及和使用,只有非常少数的网站依然在用浮动来布局
  • 为什么需要flex布局

    • 长久以来,CSS 布局中唯一可靠且跨浏览器兼容的布局工具只有 floatspositioning
    • 但是这两种方法本身存在很大的局限性,并且用于布局实在是无奈之举

3. flex布局兼容性

  • 可以在 caniuse 上查询到具体的兼容性

4. flex布局的重要概念

  • 两个重要的概念

    • 开启了 flex 布局的元素叫 flex container

    • flex container 里面的直接子元素叫做 flex item

  • 当flex container中的子元素变成了flex item时,具备一下特点

    • flex item的布局将受flex container属性的设置来进行控制和布局
    • flex item不再严格区分块级元素和行内级元素
    • flex item 的float,clear,vertical-algin属性将失效
    • flex item默认情况下是包裹内容的,但是可以设置宽度和高度
  • 设置 display 属性为 flex 或者 inline-flex 可以成为 flex container

    • flex:flex container 以 block-level 形式存在
    • inline-flex:flex container 以 inline-level 形式存在

5. flex布局的模型

  • 容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)
  • 主轴的开始位置叫做main start,结束位置叫做main end
  • 交叉轴的开始位置叫做cross start,结束位置叫做cross end
  • 项目默认沿主轴排列
  • 单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size

6. flex container属性

6.1. flex-direction

  • 看flex-direction设置谁为主轴,剩下的就是侧轴

  • flex items 默认都是沿着 main axis(主轴)从 main start 开始往 main end 方向排布

  • flex-direction 决定了主轴的方向,有 4 个取值

    属性值 说明
    row 从左到右,默认
    row-reverse 从右到左
    column 从上到下
    column-reverse 从下到上

6.2. flex-wrap

  • 默认情况下,项目都排在一条线上,flex布局中默认不换行
  • flex-wrap 决定了 flex container是单行还是多行
属性值 说明
nowrap 不换行(默认)
wrap 换行
wrap-reverse 多行(对比 wrap,cross start 与 cross end 相反)
第一行在下方

6.3. flex-flow

  • flex-flow 属性是 flex-direction 和 flex-wrap 的简写

    • flex-flow: <flex-direction> || <flex-wrap>
      
      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
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128

      - 顺序任何, 并且都可以省略



      ## justify-content

      - justify-content 决定了 flex items 在 main axis上的对齐方式

      | 属性值 | 说明 | 图形化 |
      | ------------- | ------------------------------------------------------------ | :------------------------: |
      | flex-start | 默认值,与main start对齐 | ![](/jc-flex-start.png) |
      | flex-end | 与main end对齐 | ![](/jc-flex-end.png) |
      | center | 在main axis居中对齐 | ![](/jc-center.png) |
      | space-between | 首个flex item放置于起点<br>末尾flex item放置于终点<br>其余flex items等分剩余空间 | ![](/jc-space-between.png) |
      | space-around | 每个flex items两边都有间距<br>每个flex items两边分配相同的空间<br/>flex item 与 cross start、cross end 的间距是flex items之间间距的一半 | ![](/jc-space-around.png) |
      | space-evenly | 每个flex items两端都有间距<br>所有的空间等分<br/>flex item 与 cross start、cross end 的间距等于flex items之间的距离 | ![](/jc-space-evently.png) |



      ## align-items 单行

      - align-items 决定了flex items在 cross axis 上的对齐方式
      - flex items为单行时使用

      | 属性值 | 说明 | 图形化 |
      | ---------- | ------------------------------------------------------------ | :----------------------: |
      | normal | 默认值,在弹性布局中,效果和stretch一样 | |
      | stretch | 当flex items在 cross axis 方向的 size 为 auto 时,即高度为auto或不设置高度时,自动拉伸至填充容器 | ![](./ai-stretch.png) |
      | flex-start | 与 cross start 对齐 | ![](./ai-flex-start.png) |
      | flex-end | 与 cross end 对齐 | ![](./ai-flex-end.png) |
      | center | 在 cross axis 居中对齐 | ![](./ai-center.png) |
      | baseline | 与基准线对齐<br/>可以跟字号有关,跟vertical-align属性有关 | ![](./ai-baseline.png) |



      ## align-content 多行

      - align-content 决定了多行flex items在 cross axis 上的对齐方式,用法与 justify-content 类似
      - 并且只能用于子项出现换行的情况,单行下无效

      | 属性值 | 说明 | 图形化 |
      | ------------- | ------------------------------------------------------------ | -------------------------- |
      | stretch | 默认值,flex items不设置高度的情况下,轴线高度占满整个cross axis | ![](/ac-stretch.png) |
      | flex-start | 与 cross start 对齐 | ![](/ac-flex-start.png) |
      | flex-end | 与 cross end 对齐 | ![](/ac-flex-end.png) |
      | center | 在 cross axis 居中对齐 | ![](/ac-center.png) |
      | space-between | 每根轴线之间的间隔都相等<br/>与 cross start、cross end两端对齐 | ![](/ac-space-between.png) |
      | space-around | 每根轴线两侧的间隔都相等<br/>轴线 与 cross start、cross end 的间距是轴线之间间距的一半 | ![](/ac-space-around.png) |
      | space-evently | 存在兼容性问题 | |



      # flex-item属性

      ## order

      - order 决定了 flex items 的排布顺序
      - 可以设置任意`整数`(正整数、负整数、0),`值越小就越排在前面`
      - 默认值是 0

      ![](/order.png)

      ## align-self

      - align-self 允许单个项目有与其他项目不一样的对齐方式,可覆盖 flex container 设置的 align-items
      - auto(默认值):遵从 flex container 的 align-items 设置
      - stretch、flex-start、flex-end、center、baseline,效果跟 align-items 一致

      ![](/algin-self.png)



      ## flex-grow 扩展

      - flex-grow 决定了 flex items 如何扩展(拉伸/成长)
      - 可以设置任意`非负数字(正小数、正整数、0),默认值是 0`
      - 当 flex container 在 main axis 方向上`有剩余 size` 时,flex-grow 属性才会有效

      - 如果所有 flex items 的 flex-grow 总和 sum 超过 1,每个 flex item 扩展的 size 为
      - flex container 的剩余 size x ( flex-grow / sum)

      - flex items 扩展后的最终 size 不能超过 max-width 或 max-height

      ![](/flex-grow.png)



      ## flex-shrink 收缩

      - flex-shrink 决定了 flex items 如何收缩(缩小)
      - 可以设置任意`非负数字(正小数、正整数、0)`
      - 默认值为1,多个元素在同一行时默认会显示压缩
      - 当 flex items 在 main axis 方向上`超过了 flex container 的 size`,flex-shrink 属性才会有效

      - 如果所有 flex items 的 flex-shrink 总和超过 1,每个 flex item 收缩的 size为
      - flex items 超出 flex container 的 size x ( 收缩比例 / 所有 flex items 的收缩比例之和)

      - flex items 收缩后的最终 size 不能小于 min-width 或 min-height



      ## flex-basis

      - flex-basis 用来设置 flex items 在 main axis 方向上的基础尺寸
      - auto(默认值)
      - 具体的宽度数值(100px)



      ### 案例

      当遇到长单词,原无法显示的剩余内容时,元素会自动进行拉伸

      ![](/flex-basis.png)

      - 设置 div.item2元素 width:120px; 时,aaaaa_bbbbb_ccccc_ddddd无法在一行中完整显示,会被剪裁

      - 改为 flex-basis:120px; 或者 auto时,自动拉伸

      - HTML

      ```html
      <div class="content">
      <div class="item item1">1</div>
      <div class="item item2">aaaaa_bbbbb_ccccc_ddddd</div>
      <div class="item item3">3</div>
      </div>
  • CSS

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    .content {
    display: flex;
    width: 400px;
    height: 200px;
    background-color: orange;
    }
    .item {
    width: 120px;
    height: 120px;
    }
    .item1 {
    background-color: bisque;
    }
    .item2 {
    width: auto;
    flex-basis: 120px;
    background-color: pink;
    }
    .item3 {
    background-color: yellow;
    }
  • 同时设置 width:120px; 和 flex-basis:120px; 时,flex-basis其实是生效的,但是设置的width又将尺寸限制在120px

6.3.1. 决定基础尺寸的因素

  • 决定 flex items 最终基础尺寸的因素,从优先级高到低
    • max-width/max-height/min-width/min-height
    • flex-basis
    • width/height
    • 内容本身的 size

6.4. flex属性

  • flex 是 flex-grow || flex-shrink || flex-basis 的简写,flex 属性可以指定1个,2个或3个值
1
flex = none |[ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ] 
  • 单值语法:值必须为以下其中之一

    • 一个无单位数(number):它会被当作 flex-grow 的值
    • 一个有效的宽度(width)值: 它会被当作 flex-basis 的值
    • 关键字none,auto
      • flex: flex-grow flex-shrink flex-basis
      • none 相当于 flex: 0 0 auto
      • auto 相当于 flex: 1 1 auto
  • 双值语法:第一个值必须为一个无单位数,并且它会被当作 flex-grow 的值

    • 第二个值必须为以下之一
      • 一个无单位数:它会被当作 flex-shrink 的值
      • 一个有效的宽度值:它会被当作 flex-basis 的值
  • 三值语法

    • 第一个值必须为一个无单位数,并且它会被当作 flex-grow 的值
    • 第二个值必须为一个无单位数,并且它会被当作 flex-shrink 的值
    • 第三个值必须为一个有效的宽度值, 并且它会被当作 flex-basis 的值

7. 多列行个数不同布局问题

7.1. 问题

  • 设置主轴上元素贴边对齐
  • 希望1,4,5号元素贴边的情况下,6,7号元素布局跟2,3号元素一样
  • 情况出现在最后一行元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.content>.item.item$*10{$}

.content {
width: 500px;
background-color: orange;

display: flex;
justify-content: space-between;
flex-wrap: wrap;
}

.item {
width: 110px;
height: 140px;
background-color: pink;

margin-bottom: 5px;
}

7.2. 解决

7.2.1. 计算间距

  • 方法一:舍弃space-between,通过计算元素之间的距离来达到效果
    • 父盒子宽度(500) - 子盒子宽度(110)*4 = 剩余空间(60)
    • 剩余空间(60)/(4个元素3个间隙)3 = 20px,元素之间距离为20px,即margin-right
    • 但要去掉每列最后一个元素的margin-right
  • 缺点:方法需要计算,不利于维护
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.content {
width: 500px;
background-color: orange;

display: flex;
/* justify-content: space-between; */
flex-wrap: wrap;
}

.item {
width: 110px;
height: 140px;
background-color: pink;

margin-bottom: 5px;

margin-right: 20px;
}
.item:nth-child(4n){
margin-right: 0;
}

7.2.2. 添加新元素

  • 方法二:容器内放置新元素

    • span/div/p/i/…都可以

    • 新元素的宽度等于子元素的宽度

      • 新元素没有设置高度而不会显示
    • 新元素的个数等于列数-2

      • 当元素个数为5,第2行有3个元素: div.item5, 新元素, 新元素,div.item5因为space-between放置在贴main start位置
      • 当元素个数为6,第2行有4个元素: div.item5, div.item6, 新元素, 新元素,占满
      • 当元素个数为7,第2行还是有4个元素:div.item5, div.item6, div.item7, 新元素,占满
      • 当元素个数为8,第2行还是有4个元素:div.item5, div.item6, div.item7, div.item8,占满
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    .content>.item.item$*7{$}+span*2

    .content {
    width: 500px;
    background-color: orange;

    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
    }

    .item {
    width: 110px;
    height: 140px;
    background-color: pink;

    margin-bottom: 5px;
    }
    .content > span {
    width: 110px;
    }

7.2.3. 采用 grid布局

本文结束  感谢您的阅读