Flex布局-容器项

弹性盒子是一种用于 按行 或 按列的一维布局方法.

元素可以膨胀以填充额外的空间, 也可以 收缩 以适应更小的空间.

flex 重点概览

对于 flex 重要的理解点在于:

  • 主轴与交叉轴
  • 换行与缩写
  • 主轴对齐方式
  • 交叉轴对齐方式

基于了解完上面的内容, 我们能用 flex 布局实现如下几种最常见的布局:

  • 内联和块的 上下左右居中布局
  • 不定项居中布局
  • 均分列布局
  • 组合嵌套布局

接着是关于 flex-子项 的重点:

  • flex-grow: 扩展比例
  • flex-shrink 收缩比例
  • flex-basis 及flex缩写
  • order 与 align-self

最后同样是基于子项的属性, 完成一些常用的子项布局:

  • 等高布局
  • 两列与三列布局
  • 粘性页脚布局
  • 溢出项布局

可以发现这个 flex 是真的很强, 相对于上面的内容如果用定位 + 浮动的方式, 搞起来还是超级麻烦的哦

主轴与交叉轴

要形成 flex 布局, 首先需要一个父容器 flex-container, 然后是里面的子项 flex-item.

主轴

主轴 main-axis 默认是水平轴, 交叉轴 cross-axis 则垂直于主轴, 因此子元素默认是水平排列的. 要注意的是主轴和交叉轴, 包括起点, 终点都是可以互换的, 非常灵活.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>flex</title>
  <style>
    .main {
      width: 500px;
      height: 500px;
      background-color: pink;
      /* 这里用的是 display 的内部值属性 */
      display: flex;
    }
    .main div {
      width: 100px;
      height: 100px;
      background-color: skyblue;
    }
  </style>
</head>
<body>
  <div class="main">
    <div>1</div>
    <div>2</div>
    <div>3</div>
  </div>
</body>
</html>

特别要注意区分 flex容器 和 flex子项的属性, 千万别写混了.

flex 容器属性 flex 子项属性
flex-direction order
flex-wrap flex-grow
flex-flow flex-shrink
justify-content flex-basis
align-items flex
align-content align-self

交叉轴

flex-direction 其实就是设置主轴是行还是列, 且起始位置是否要逆反而已啦. 要列它一共有 4个属性值:

  • row (默认)
  • row-reverse
  • column
  • column-reverse

默认是水平布局, 当 flex-direction: row-reverse 时候, 子项从右往左排列.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>flex</title>
  <style>
    .main {
      width: 500px;
      height: 500px;
      background-color: pink;
      /* 这里用的是 display 的内部值属性 */
      display: flex;
      /* 改变主轴起点位置, 水平时, 左->右; reverse: 从右->左 */
      flex-direction: row-reverse;
    }
    .main div {
      width: 100px;
      height: 100px;
      background-color: skyblue;
    }
  </style>
</head>
<body>
  <div class="main">
    <div>1</div>
    <div>2</div>
    <div>3</div>
  </div>
</body>
</html>

当我们改变为垂直布局时, flex-direction: 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>flex</title>
  <style>
    .main {
      width: 500px;
      height: 500px;
      background-color: pink;
      display: flex;
      /* 改变主轴起点位置, 垂直时, 默认上->下; reverse: 下 -> 上 */
      /* flex-direction: column; */
      flex-direction: column-reverse;
    }
    .main div {
      width: 100px;
      height: 100px;
      background-color: skyblue;
    }
  </style>
</head>
<body>
  <div class="main">
    <div>1</div>
    <div>2</div>
    <div>3</div>
  </div>
</body>
</html>

换行与缩写

flex-wrap 用来设置当子项宽度超出容器时, 是否换行的问题, 主要有 3 个值:

  • nowrap (默认) , 默认不换行, 进行一行的压缩, 宽度不会溢出父容器, 内容往里压缩啦. 但超级多也会溢出.
  • wrap
  • wrap-reverse

当弹性的子元素没有 width 时, 宽度会根据内容撑开; 当不设置 height 时, 会自动撑满容器

当主轴是 row 时:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>flex</title>
  <style>
    .main {
      width: 500px;
      height: 500px;
      background-color: pink;
      display: flex;
      /* 元素尺寸超出, 可设置换行, 但是按父容器百分比平分, 2行的话就是 50% 的位置 */
      /* 但如果父容器没有高度的话, 那就顺势挨在一起了. */
      /* flex-wrap: wrap; */
      /* reverse 也可设置从底部开始折行, 但这种用得比较少 */
      flex-wrap: wrap-reverse;
    }
    .main div {
      width: 100px;
      height: 100px;
      background-color: skyblue;
    }
  </style>
</head>
<body>
  <div class="main">
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>4</div>
    <div>5</div>
    <div>6</div>
    <div>7</div>
    <div>8</div>
    <div>9</div>
    <div>10</div>
    <div>11</div>
  </div>
</body>
</html>

当主轴是 column 时:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>flex</title>
  <style>
    .main {
      width: 500px;
      height: 500px;
      background-color: pink;
      display: flex;
      /* 元素尺寸超出, 可设置换列, 但是按父容器百分比平分, 2列的话就是 50% 的位置 */
      /* 但如果父容器没有宽的话, 那就顺势挨在一起了. */
      flex-direction: column;
      /* flex-wrap: wrap; */
      /* reverse 也可设置从底部开始折行, 但这种用得比较少 */
      flex-wrap: wrap-reverse;
    }
    .main div {
      width: 100px;
      height: 100px;
      background-color: skyblue;
    }
  </style>
</head>
<body>
  <div class="main">
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>4</div>
    <div>5</div>
    <div>6</div>
    <div>7</div>
    <div>8</div>
    <div>9</div>
    <div>10</div>
    <div>11</div>
  </div>
</body>
</html>

但需注意的是, flex 布局更倾向于一维的布局, 如果是设计行和列的那还是得 grid 比较适合.

通常我用flex最多的就是, 一维横向, 子元素水平垂直居中就可以啦.

flex-flow

这个属性其实就是 flex-direction 和 flex-wrap 的缩写而已啦.

  <style>
    .main {
      width: 500px;
      height: 500px;
      background-color: pink;
      display: flex;

      /* flex-direction: column;
      flex-wrap: wrap; */
      /* 上面两行可简写为一行 */
      /* flex-flow: column wrap; */
      flex-flow: wrap;

    }
    .main div {
      width: 100px;
      height: 100px;
      background-color: skyblue;
    }
  </style>

为了降低记忆难度, 我感觉缩写啥, 就直接全写得了, 也不是那么费事.

主轴对齐

justify-content 主轴对齐, 即设置主轴元素的对齐方式, 主要有如下:

  • flex-start (默认)
  • flex-end
  • center
  • space-around
  • space-between
  • space-evenly
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>flex</title>
  <style>
    .main {
      width: 500px;
      height: 500px;
      background-color: pink;
      display: flex;

      /* 子元素默认对齐方式是 flex-start 紧挨着 */
      /* justify-content: flex-start; */

      /* 右对齐方式 */
      /* justify-content: flex-end; */

      /* 居中对齐 */
      /* justify-content: center; */

      /* 分散对齐, 最左/最右 的空间是一致的, 若不设置父容器宽, 则默认均分浏览器视口  */
      /* justify-content: space-around; */

      /* 两端对齐, 两侧分别顶到两个断点, 再来进行平分剩余空间 */
      /* justify-content: space-between; */

      /* 平均分配, 子项之间的距离是相等的 */
      justify-content: space-evenly;

    }
    .main div {
      width: 100px;
      height: 100px;
      background-color: skyblue;
    }
  </style>
</head>
<body>
  <div class="main">
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>4</div>
  </div>
</body>
</html>

当主轴为 cloumn 时, 也是一样的, 相当于转换一下而已.

  <style>
    .main {
      width: 500px;
      height: 500px;
      background-color: pink;
      display: flex;

      flex-direction: column;

      /* 子元素默认对齐方式是 flex-start 列 */
      justify-content: flex-start;

      /* 下对齐方式 */
      /* justify-content: flex-end; */

      /* 居中对齐 */
      /* justify-content: center; */

      /* 分散对齐, 最上/最下 的空间是一致的, 不设高时候, 按内容撑开 */
      /* justify-content: space-around; */

      /* 两端对齐, 两侧分别顶到两个断点, 再来进行平分剩余空间 */
      /* justify-content: space-between; */

      /* 平均分配, 子项之间的距离是相等的 */
      /* justify-content: space-evenly; */

    }
    .main div {
      width: 100px;
      height: 100px;
      background-color: skyblue;
    }
  </style>

交叉轴对齐

交叉轴的对齐方式比主轴要更强大一些, 因为它有两个兄弟呀.

align-content

这个 align-content 和 justify-content 还是很像的, 唯一的特点是它必须要有换行才能生效.

  • strech (默认)
  • flex-start
  • flex-end
  • center
  • space-around
  • space-between
  • space-evenly
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>align-content</title>
  <style>
    .main {
      width: 500px;
      height: 500px;
      background-color: pink;
      display: flex;

      flex-wrap: wrap;
      /* 当不换行的时候, align-content 不生效 */
      /* align-content: flex-end; */
      /* align-content: stretch; */
      /* align-content: space-around; */
      /* align-content: space-between; */
      align-content: space-evenly;

    }
    .main div {
      width: 100px;
      height: 100px;
      background-color: skyblue;
    }
  </style>
</head>
<body>
  <div class="main">
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>4</div>
    <div>5</div>
    <div>6</div>
    <div>7</div>
  </div>
</body>
</html>

align-items

它是针对容器中, 针对每一行的对齐方式, 而 align-content 是针对整体. 在实际应用中, 针对每一行的方式则用的更多些. 毕竟用 flex 是用来解决一维布局的, 换行就搞起来有点麻烦, 不如用 grid 操作.

  • stretch (默认)
  • flex-start
  • flex-end
  • center
  • baseline -- 用得少
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>align-items</title>
  <style>
    .main {
      width: 500px;
      height: 500px;
      background-color: pink;
      display: flex;

      flex-wrap: wrap;
      /* align-items: 每一行的对齐 */
      /* align-items: flex-start; */
      align-items: center;

    }
    .main div {
      width: 100px;
      height: 100px;
      background-color: skyblue;
    }
  </style>
</head>
<body>
  <div class="main">
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>4</div>
    <div>5</div>
    <div>6</div>
    <div>7</div>
  </div>
</body>
</html>

从我的应用实践中, 就水平垂直居中用的比较多一些, 其他的换行都不咋用的.

. flex-container {
    dispaly: flex;
    justify-content: center;
    align-items: center;
}

水平垂直居中布局

即容器内元素的水平和居中对齐, 根据内容.

内联元素: 文本垂直水平居中

  • 水平居中: justify-content: center;
  • 垂直居中: align-items: center
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>文字水平垂直居中</title>
  <style>
    .box {
      width: 300px;
      height: 200px;
      background-color: pink;
      /* 水平垂直居中 */
      display: flex;
      justify-content: center;
      align-items: center;
    }
  </style>
</head>
<body>
  <div class="box">哈哈哈哈哈</div>
</body>
</html>

这样就轻松搞定了. 但如果我们不用 flex 的话, 如果只是垂直居中, 就可以用 行高 = 盒子高 .

  <style>
    .box {
      width: 300px;
      height: 200px;
      background-color: pink;
      /* f水平垂直居中 */
      text-align: center;
      line-height: 200px;
    }
  </style>

但这种一旦涉及多行文字, 这种设置行高的方式就会对每行文字撑大一个空间, 就乱了. 但 flex 没有问题.

块级元素: 垂直水平居中

  • 水平居中: justify-content: center;
  • 垂直居中: align-items: center
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>块元素-水平垂直居中</title>
  <style>
    .box {
      width: 300px;
      height: 200px;
      background-color: pink;

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

如果不用 flex 的话, 我们可以通过定位来实现哈, 即 子绝父相.

  <style>
    .box {
      width: 300px;
      height: 200px;
      background-color: pink;

      /* 块元素 水平垂直居中, 子绝父相 */
      position: relative;

    }
    .box div {
      width: 100px;
      height: 100px;
      background-color: skyblue;

      /* 子: 绝对定位, 参考父元素(设置了 relative) */
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);

    }
  </style>

或者也可用 margin: auto 来做, 设置绝对定位, 然后 top / right / bottom / left 都设置为 0 即可.

  <style>
    .box {
      width: 300px;
      height: 200px;
      background-color: pink;
      position: relative;
    }
    .box div {
      width: 100px;
      height: 100px;
      background-color: skyblue;

      position: absolute;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;

      margin: auto; 
    }
  </style>

对比发现, 还是这个 flex 布局比较好用呀.

不定项居中对齐

就中间元素多少不清楚, 但需要进行居中对齐, 最常用的比如轮播图里面, 下面的切换小点点,

还有就是像页面分页器在底部的居中对齐等.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>不定项居中对齐</title>
  <style>
    .box {
      width: 300px;
      height: 150px;
      background-color: pink;

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

    .box div {
      width: 30px;
      height: 30px;
      background-color: skyblue;
      border-radius: 50%;
      margin: 10px;
    }
  </style>
</head>
<body>
  <div class="box">
    <div></div>
    <div></div>
    <div></div>
    <!-- 多项也能进行居中 -->
    <div></div>
    <div></div>
  </div>
</body>
</html>

同样如果不用 flex , 则我们可以利用 position 来做:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>定位实现: 不定项居中对齐</title>
  <style>
    .box {
      width: 300px;
      height: 150px;
      background-color: pink;
      /* 子绝父相 */
      position: relative;
      
    }

    .box section {
      /* text-align 对内联样式起作用, 块则无效 */
      text-align: center;
      width: 100%;
      position: absolute;
      bottom: 0;
      font-size: 0;
    }

    .box div {
      width: 30px;
      height: 30px;
      background-color: skyblue;
      border-radius: 50%;
      margin: 10px;

      /* inline-block: 对外是行内样式, 对内是块样式 */
      display: inline-block;
    }
  </style>
</head>

<body>
  <div class="box">
    <section>
      <div></div>
      <div></div>
      <div></div>
      <!-- 多项也能进行居中 -->
      <!-- <div></div>
          <div></div> -->
    </section>
  </div>
</body>

</html>

这个搞起来就有点麻烦, 但是也能, 不过要这样对比才能发现这个 flex 是真的香呀, 而且还是自适应的.

均分列布局

最常用的就是小程序底部的菜单栏, 将底部进行一个均分排列, 即便新增也是均分开显示哦.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>均分列布局</title>
  <style>
    .main {
      /* 块盒子不写 width 就是默认浏览器 */
      height: 200px;
      background-color: pink;

      display: flex;      
      /* 设置子元素均分列, 自适应 */
      /* justify-content: space-around; */
      /* justify-content: space-evenly; */
      justify-content: space-between;
      
      /* 可以移到底部 */
      align-items: flex-end;
      /* 左右留一点间距出来 */
      padding: 10px 20px;
      /* 保证父容器不被撑开, 设置为怪异盒模型 */
      box-sizing: border-box;
    }
    
    .main div {
      width: 30px;
      height: 30px;
      border-radius: 50%;
      background-color: skyblue;
    }
  </style>
</head>
<body>
  <div class="main">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
  </div>
</body>
</html>

同样如果不用 flex 的话, 用 float 来实现就有一点麻烦啦.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>只能固定尺寸: 均分列布局</title>
  <style>
    .main {
      height: 200px;
      background-color: pink;
      /* 要用宽度, float 分散 */
      width: 500px;
      /* 溢出则要隐藏 */
      overflow: hidden;
      box-sizing: border-box;
      /* 左右边距 */
      padding: 0 10px;
      /* 子绝父相 */
      position: relative;
    }

    .main section {
      width: 800px;
      position: absolute;
      bottom: 10px;
    }
    
    .main div {
      width: 30px;
      height: 30px;
      border-radius: 50%;
      background-color: skyblue;

      float: left;
      margin-right: 120px;
    }
  </style>
</head>
<body>
  <div class="main">
    <section>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
    </section>
  </div>
</body>
</html>

可以看到这个用浮动 + 定位来实现就要计算宽度, 有点麻烦, 而且还不能自适应, 果断废弃用 flex 呀.

子项分组布局

其实就是嵌套 flex. 比如有3个块要横向排列, 一个在左边, 另外两个靠右边, 中间空出来这种效果.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>子项分组布局</title>
  <style>
    .main {
      height: 200px;
      background-color: pink;

      display: flex;
      justify-content: space-between;
      align-items: center;
    }

    /* 右边, 即 main 下的第二个兄弟, 也进行 flex 布局 */
    .main div:nth-of-type(2) {
      display: flex;
      /* 留一点间隙 */
      margin-left: 10px;
    }

    .main .box {
      width: 50px;
      height: 100px;
      background-color: skyblue;
    }
  </style>
</head>
<body>
  <!-- 外层容器用 flex -->
  <div class="main">
    <div class="box">1</div>
    <!-- 子项也进行 flex -->
    <div>
      <div class="box">2</div>
      <div class="box">3</div>
    </div>
  </div>
</body>
</html>

这个核心在于在 html 的部分进行嵌套和包裹, 再用 flex , 能够实现效果, 但是有点麻烦. 其实有个更为简单的办法, 是通过 margin-right: auto;

Tips: 当父容器布局为 flex 时, 子项用 margin-right: auto 会将右边的元素直接挤压到右侧, 贼好用

关于 flex 父容器的相关设置和常用的布局就基本到这啦.

posted @ 2024-05-13 20:31  致于数据科学家的小陈  阅读(35)  评论(0编辑  收藏  举报