css 基础之 - flex

flex 布局很重要很核心的一个概念就是 , flex 是有两个轴, 一个主轴, 一个交叉轴. 主轴永远和交叉轴互相垂直;

在未对子元素设置任何样式时, 子元素在主轴的表现, 由子元素内容决定, 而在交叉轴上则是占满交叉轴, 即为交叉轴的 100%;

在 flex 遇到 margin 和定义宽度, 总是会遇到一些意料之外的表现. 所以尽量少的 flex 属性和其他可以改变元素宽度和高度的样式混用.

基本 html 骨架如下:

<div class="container">
    <div class="item"></item>
</div>

container 属性

1. 定义 flex 容器

container 定义 flex 布局表现.

  • display : flex ;

container 独自占一整行, 宽度为 100%;

  • display: inline-flex;

container 的宽度由子元素 item 的宽度决定. 能和行列元素 , dispaly:inline-block 的元素 , display:inline-flex 的元素并排显示在一行

2. 定义 item 的排列方向, 也就是定义主轴方向

子元素, 总是按照主轴方向进行排布.

  • flex-direction : row ; // 主轴方向为横向从左到右 →

  • flex-direction: row-reverse; // 主轴方向为横向从右到左 ←

  • flex-direction: column; // 主轴方向为竖向, 从上到下 ↓

  • flex-direction: column-reverse; // 主轴方向为竖向, 从下到上 ↑

  <style>
    * {
      margin: 0;
      padding: 0;
    }

    .container {
      background: orange;
      margin-bottom: 20px;
      display: flex;
      height: 100px;
    }

    .container-row {
      flex-direction: row;
    }

    .container-row-reverse {
      flex-direction: row-reverse;
    }

    .container-column {
      flex-direction: column;
    }

    .container-column-reverse {
      flex-direction: column-reverse;
    }

    .item {
      background: pink;
    }
  </style>
  <h3>flex-direction: row</h3>
  <div class="container container-row">
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
  </div>

  <h3>flex-direction: row-reverse</h3>
  <div class="container container-row-reverse">
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
  </div>

  <h3>flex-direction: container-column</h3>
  <div class="container container-column">
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
  </div>
  <h3>flex-direction: container-column-reverse</h3>
  <div class="container container-column-reverse">
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
  </div>

这里写图片描述

  1. 子元素 item 交叉轴的尺寸默认为容易的 100%;
  2. 不管排布方向 , 容器 container 设置 display:flex 时的默认宽度为 100% ;
  3. 不管排布方向, 容器 container 设置 display:inline-flex 时的默认宽度和高度都为子元素自适应 ;
定义对齐方式
  • 主轴对齐 : justify-cotent

    • justify-content:flex-start; // 开始对齐 ( 默认 )
    • justify-content:flex-end; // 结尾对齐
    • justify-content:center; // 中间对齐
    • justify-content:space-between; // 两端对齐,子元素间空隙相等,空隙的个数为n-1
    • justify-content:space-around; // 两端也留空隙,空隙的个数为n-1+2,但两端的空隙和子元素间的空隙并不相等,两端是其他的1/2
    • justify-content: space-evenly; // n-1+2个空隙,各空隙均等
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    .container {
      background: pink;
      margin-bottom: 20px;
      display: inline-flex;
      width: 160px;
      height: 100px;
      margin-right: 10px;
    }

    .container-start {
      justify-content: flex-start;
    }
    .container-end {
      justify-content: flex-end;
    }
    .container-center {
      justify-content: center;
    }
    .container-between {
      justify-content: space-between;
    }
    .container-around {
      justify-content: space-around;
    }
    .container-evenly {
      justify-content:space-evenly ; 
    }

    .item {
      background: orange;
    }
  </style>
  <h3>justify-content:</h3>
  <div class="container container-start">
    <div class="item">-</div>
    <div class="item">start</div>
    <div class="item">-</div>
  </div>
  <div class="container container-end">
    <div class="item">-</div>
    <div class="item">end</div>
    <div class="item">-</div>
  </div>
  <div class="container container-center">
    <div class="item">-</div>
    <div class="item">center</div>
    <div class="item">-</div>
  </div>
  <div class="container container-between">
    <div class="item">-</div>
    <div class="item">between</div>
    <div class="item">-</div>
  </div>
  <div class="container container-around">
    <div class="item">-</div>
    <div class="item">around</div>
    <div class="item">-</div>
  </div>
  <div class="container container-evenly">
    <div class="item">-</div>
    <div class="item">evenly</div>
    <div class="item">-</div>
  </div>

效果图如下:

这里写图片描述

- justify-content:flex-start; // 开始对齐 ( 默认 )
- justify-content:flex-end; // 结尾对齐
- justify-content:center; // 中间对齐
- justify-content:space-between; // 两端对齐,子元素间空隙相等,空隙的个数为n-1
- justify-content:space-around; // 两端也留空隙,空隙的个数为n-1+2,但两端的空隙和子元素间的空隙并不相等,两端是其他的1/2
- justify-content: space-evenly; // n-1+2个空隙,各空隙均等
  • 交叉轴单行对齐: align-items

    • align-items:flex-start; // 开始对齐
    • align-items:flex-end; // 结尾对齐
    • align-items:center; // 居中对齐
    • align-items:stretch; // 拉升到容器交叉轴大小 ( 默认 )
    • align-items:baseline; // 基线对齐
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    .container {
      background: pink;
      margin-bottom: 20px;
      display: inline-flex;
      width: 160px;
      height: 100px;
      margin-right: 10px;
    }

    .container-start {
      align-items: flex-start;
    }
    .container-end {
      align-items: flex-end;
    }
    .container-center {
      align-items: center;
    }
    .container-stretch {
      align-items: stretch;
    }
    .container-baseline {
      align-items: baseline;
    }

    .item {
      background: orange;
    }
  </style>
  <h3>align-items:</h3>
  <div class="container">
    <div class="item">-</div>
    <div class="item">default</div>
    <div class="item">-</div>
  </div>
  <div class="container container-start">
    <div class="item">-</div>
    <div class="item">start</div>
    <div class="item">-</div>
  </div>
  <div class="container container-end">
    <div class="item">-</div>
    <div class="item">end</div>
    <div class="item">-</div>
  </div>
  <div class="container container-center">
    <div class="item">-</div>
    <div class="item">center</div>
    <div class="item">-</div>
  </div>
  <div class="container container-stretch">
    <div class="item">-</div>
    <div class="item">stretch</div>
    <div class="item">-</div>
  </div>
  <div class="container container-baseline">
    <div class="item">-</div>
    <div class="item">baseline</div>
    <div class="item">-</div>
  </div>

效果如下:
这里写图片描述

- align-items:flex-start; // 开始对齐
- align-items:flex-end; // 结尾对齐
- align-items:center; // 居中对齐
- align-items:stretch; // 拉升到容器交叉轴大小 ( 默认 )
- align-items:baseline; // 基线对齐

当多个 inline-flex 同处一行, 而 align-item 不一致时, 就如上图所示.

  • 交叉轴多行对齐: align-content

    • align-content:flex-start; //
    • align-content:flex-end;
    • align-content:center;
    • align-content:stretch;
    • align-content:space-between;
    • align-content:space-around;
    • align-content:space-evenly;
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    .container {
      background: pink;
      margin-bottom: 20px;
      display: inline-flex;
      width: 160px;
      height: 100px;
      margin-right: 10px;
      flex-wrap: wrap;
    }

    .container-start {
      align-content: flex-start;
    }
    .container-end {
      align-content: flex-end;
    }
    .container-center {
      align-content: center;
    }
    .container-stretch {
      align-content: stretch;
    }
    .container-between{
      align-content: space-between;
    }
    .container-around {
      align-content: space-around;
    }
    .container-evenly {
      align-content: space-evenly;
    }

    .item {
      background: orange;
      width:80px;
    }
  </style>
  <h3>align-content:</h3>
  <div class="container">
    <div class="item">-</div>
    <div class="item">default</div>
    <div class="item">-</div>
  </div>
  <div class="container container-start">
    <div class="item">-</div>
    <div class="item">start</div>
    <div class="item">-</div>
  </div>
  <div class="container container-end">
    <div class="item">-</div>
    <div class="item">end</div>
    <div class="item">-</div>
  </div>
  <div class="container container-center">
    <div class="item">-</div>
    <div class="item">center</div>
    <div class="item">-</div>
  </div>
  <div class="container container-stretch">
    <div class="item">-</div>
    <div class="item">stretch</div>
    <div class="item">-</div>
  </div>
  <div class="container container-between">
    <div class="item">-</div>
    <div class="item">between</div>
    <div class="item">-</div>
  </div>
  <div class="container container-around">
    <div class="item">-</div>
    <div class="item">around</div>
    <div class="item">-</div>
  </div>
  <div class="container container-evenly">
    <div class="item">-</div>
    <div class="item">evenly</div>
    <div class="item">-</div>
  </div>

效果如下:
这里写图片描述

基本类似 justify-content 的表现. 只是是相对多行内容来说 , 以交叉轴为对齐方向.
这里, 注意需 container 设置 flex-wrap:wrap 样式强制子元素换行.

定义主轴方向是否换行
  • flex-wrap:nowrap; // (默认),不换行
  • flex-wrap:wrap; // 强制换行
  • flex-wrap:wrap-reverse; // 强制反向换行
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    .container {
      background: pink;
      margin-bottom: 20px;
      display: inline-flex;
      width: 160px;
      height: 140px;
      margin-right: 10px;
    }

    .container-nowrap {
      flex-wrap: nowrap;
    }
    .container-wrap{
      flex-wrap: wrap;
    }
    .container-wrap-reverse{
      flex-wrap: wrap-reverse;
    }

    .item {
      background: orange;
      width:60px;
      height: 40px;
      border:1px solid red;
    }
  </style>
  <h3>flex-wrap:</h3>
  <div class="container">
    <div class="item">1</div>
    <div class="item">default</div>
    <div class="item">2</div>
  </div>
  <div class="container container-nowrap">
    <div class="item">1</div>
    <div class="item">nowrap</div>
    <div class="item">2</div>
  </div>
  <div class="container container-wrap">
    <div class="item">1</div>
    <div class="item">wrap</div>
    <div class="item">2</div>
  </div>
  <div class="container container-wrap-reverse">
    <div class="item">1</div>
    <div class="item">wrap-reverse</div>
    <div class="item">2</div>
  </div>

效果如下:

这里写图片描述

主轴方向和换行的合并简写: flex-flow: row nowrap;( 默认表现: 横向不换行 )

items 属性

1. order 自定义主轴上排列位置 , 可正数可负数, 默认值为0 ;

在同一个 flex container 容器下, 所有直接子元素会按设置的 order 的大小排序来显示. 负数 > 0 ( 默认 ) > 正数

  <style>
    * {
      margin: 0;
      padding: 0;
    }

    .container {
      background: pink;
      display: flex;
      height: 140px;
    }
    .item {
      background: orange;
      width: 60px;
      border-right: 1px solid red;
    }
    .order-less-zero{
      order: -1;
    }
    .order-three {
      order: 3;
    }
    .order-one {
      order: 1;
    }
    .order-zero {
      order: 0;
    }
  </style>
  <h3>order:</h3>
  <div class="container">
    <div class="item order-three">3</div>
    <div class="item order-one">1</div>
    <div class="item order-zero">0</div>
    <div class="item order-less-zero">-1</div>
    <div class="item order-default">default</div>
  </div>

效果如下:

这里写图片描述

2. flex-grow , 子元素主轴上所占比例, 默认值为 0;
  1. item 只有一个设置特殊值, 比如默认的都是 0 , 给其中某一个设置特殊值 ( 非负数 ) 时, 特殊的 item 占满剩余空间.
  2. 当设置所有 itemflex-grow 为 1 , 一个特殊的为 2 的话, 则该特殊元素, 是比其他设置为 1 的要宽一些, 但却并不是严格的设置的 flex-grow 的倍数的关系.
  3. 多个不同的 flex-grow ? 没多大意义. 因为简单的两倍关系都没办法保证.
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    .container {
      background: pink;
      display: flex;
      height: 140px;
      margin-bottom: 10px;
    }

    .item {
      background: orange;
      border-right: 1px solid red;
      padding:0 10px;
    }

    .one-grow .item-special {
      flex-grow: 1;
    }

    .two-grow .item{
      flex-grow: 1;
    }
    .two-grow .grow-2{
      flex-grow: 4;
    }

    .many-grow .grow-1{
      flex-grow: 1;
    }
    .many-grow .grow-2{
      flex-grow: 2;
    }
    .many-grow .grow-3{
      flex-grow: 3;
    }
    .many-grow .grow-4{
      flex-grow: 4;
    }
  </style>
  <h3>one grow:</h3>
  <div class="container one-grow">
    <div class="item">3</div>
    <div class="item">发发呆发发呆发</div>
    <div class="item">内容不定宽</div>
    <div class="item item-special">特殊值的 grow flex-grow:1</div>
  </div>
  <h3>two grow:</h3>
  <div class="container two-grow">
    <div class="item">3</div>
    <div class="item">发发呆发发呆发</div>
    <div class="item">内容不定宽</div>
    <div class="item grow-2">2</div>
    <div class="item grow-2">内容不定宽123大师傅</div>
  </div>

这里写图片描述

可以看出, two-grow 中设置不同的 flex-grow , 效果真的预料不到.
flex-grow:2 ; 的 并不一定是 flex-grow:1 的两倍, 设置可能还小于.
鸡肋.
在其他子元素, 默认为0 , 设置一个元素为 大于0 的值, 可以实现:
1. 单个元素可以占满容器的主轴
2. 在有其他的元素时, 可以占满剩下的所有空间.

flex-shrink ; 当父容器不足以排列所有的子元素, 各个元素压缩的比例,
  1. 默认为 1 , 也就是各个元素都压缩相同的空间
  2. 全部默认为 1 , 一个特殊的为 2 时, 为 2 的压缩比例就大一点.
  3. 超出父容器部分将由每个子元素消化,即单个子元素每个减少宽度以不超出容器.比如5个元素,容器超出200px, 那么每个元素则需在原来的基础上减少40px;而假如5个元素的flex:shrink分别为1:1:1:1:6, 那么结果则是最后一个减少120px
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    .container {
      background: pink;
      display: flex;
      height: 140px;
      margin-bottom: 10px;
    }

    .item {
      background: orange;
      border-right: 1px solid red;
      box-sizing: border-box;
      width: 200px;
    }

    .shrink-6 {
      flex-shrink: 6;
    }
  </style>
  <h3>shrink:</h3>
  <div class="container">
    <div class="item">1</div>
    <div class="item">1</div>
    <div class="item">1</div>
    <div class="item">1</div>
    <div class="item shrink-6">6</div>
  </div>

这里写图片描述

flex-basis ; 可以用来定义各个元素之间的比例.

在压缩的时候, 始终保持 basis 的比例.

比如 5 个子元素 , 4个设置为 10% , 1个设置为 60%;
那么容器宽度为 1000 时, 就是 4个元素为 100 , 另一个为 600
如果容器宽度为 200 时, 就是 4个元素为 20 . 另一个为 120;

又比如5个元素, 1个设置 flex-basis 为 100px , 3个设置为10%, 1个设置为 60% ;
那么容器宽度为500px 时, 先算出各元素的应该有的宽度 , 100:50:50:50:300 也就是 2:1:1:1:6 ; 那么 flex-basis 设置为100的宽度应该就是差不多 500* 2/11 = 95px

flex-basis 和 flex-shrink 类似, 就是先要得出每一个元素所占的比例,
flex-basis 为正向比例, 占多少比例乘以现在容器的宽度就是元素的宽度;
而 flex-shrink 则是反向, 先算出要缩减的比例, 然后按比例在每一个元素上面销掉.

align-self , 重定义交叉轴的对齐方式
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    .container {
      background: pink;
      display: flex;
      height: 140px;
      margin-bottom: 10px;
      align-items: center;
    }

    .item {
      background: orange;
      border-right: 1px solid red;
      box-sizing: border-box;
      flex-basis: 20%;
    }

    .align-self {
      align-self: flex-start;
    }
  </style>
  <div class="container">
    <div class="item">法法阿凡达</div>
    <div class="item">1</div>
    <div class="item">1</div>
    <div class="item">1</div>
    <div class="item align-self">6</div>
  </div>

这里写图片描述

flex 应用场景

  • 子元素不定宽高居中

flex + justify-content: center + align-items: center;

  <style>
    * {
      margin: 0;
      padding: 0;
    }

    .container {
      background: pink;
      height: 200px;

      display: flex; 
      justify-content: center;
      align-items: center;

    }
    .inner{
      height: 80px;
      width:80px;
      background:orange;
    }
  </style>
  <div class="container">
    <div class="inner">
    </div>
  </div>
  • 分列布局
.container{
    display:flex;
}
.left{
    order:-1;
    flex-basis:100px;
}
.main{
    flex-grow:1;
}
.right{
    flex-basis:100px;
}

<div class="container">
    <div class="main">main</div>
    <div class="left">left</div>
    <div class="right">right</div>
</div>
  • 类似购物车 toolbar
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    body {
      color: #f5f5f5;
    }

    .tool-bar {
      position: fixed;
      bottom: 0;
      left: 0;
      width: 100%;
      height: 50px;
      background: #fff;
      display: flex;
    }

    button {
      appearance: none;
      -webkit-appearance: none;
      background: transparent;
      border: none;
      color: #333;
      padding: 0;
      margin: 0;
    }
    .tool-bar-sm {
      display: flex;
    }
    .tool-bar-sm button {
      width: 50px;
      box-sizing: border-box;
      border-right: 1px solid #e1e1e1;
      border-top: 1px solid #e1e1e1;
    }
    .tool-bar-lg {
      flex-grow: 1;
      display: flex;
    }
    .tool-bar-lg button {
      flex-basis: 100%;
      text-align: center;
      color:#fff;
    }
    .add-shopcar{
      background: #ff9600;
    }
    .buy-now{
      background: #e4393c;
    }
  </style>
  <div class="tool-bar">
    <div class="tool-bar-sm">
      <button>评论</button>
      <button>点赞</button>
      <button>收藏</button>
    </div>
    <div class="tool-bar-lg">
      <button class="add-shopcar">加入购物车</button>
      <button class="buy-now">立即购买</button>
    </div>
  </div>

效果如下:

这里写图片描述

拆分小按钮组 和 大按钮组,
小按钮组每个按钮固定宽度
大按钮组占据所有非小按钮组的空间. 每个按钮设置 flex-basis 为100% , 保证每个大按钮占据同样的宽度 , 即 宽度/个数 的 宽度.
效果: 小按钮始终保持定义的宽度, 而大按钮则根据屏幕宽度自适应. 添加删除按钮, 都不影响布局效果.

  • 多列布局

justify-content:space-between; 虽然可以实现多个元素之间保持相等的间距. 但是在三列中, 碰到最后剩余两个数据的时候, 就会出现, 两个元素靠两边对齐, 中间空缺. 所以此处只借用 flex 布局弥补 float 布局的, 左边元素高出哪怕一个像素, 也会阻挡, 元素不能往左浮的尴尬.

  <style>
    * {
      margin: 0;
      padding: 0;
    }

    ul {
      margin-left: -18px;
      margin-right: 0;
      display: flex;
      flex-wrap: wrap;
      /* justify-content: space-between; */
    }

    li {
      list-style: none;
      width: 25%;
      height: 80px;
      margin-bottom: 10px;
      background: pink;
    }
    .tall{
      height: 86px;
    }
    .inner {
      margin-left: 18px;
      background: orange;
    }
  </style>

  <ul>
    <li>
      <div class="inner">1</div>
    </li>
    <li class="tall">
      <div class="inner">2</div>
    </li>
    <li>
      <div class="inner">3</div>
    </li>
    <li>
      <div class="inner">4</div>
    </li>
    <li>
      <div class="inner">5</div>
    </li>
    <li>
      <div class="inner">5</div>
    </li>
  </ul>

效果如下:

这里写图片描述

也就是说, 第2块, 就算高度是超出了其他, 第5块也是能排在最左边. 而用浮动, 那第5块会被挡在第2块右边.

其他参考

猜你喜欢

转载自blog.csdn.net/haokur/article/details/80550097