CSS Flexbox布局(Flexible Box Layout)3

183 阅读9分钟

Flexbox 使得很多以前需要复杂 hack(如 float + clear,inline-block + vertical-align)才能实现的布局变得非常简单,尤其是在处理对齐和空间分配方面。

核心概念

理解 Flexbox 的关键在于掌握两个核心概念:Flex 容器 (Flex Container)Flex 项目 (Flex Items) ,以及两条轴线:主轴 (Main Axis)交叉轴 (Cross Axis)

  1. Flex 容器 (Flex Container):

    • 应用了 display: flex; 或 display: inline-flex; 的父元素。
    • 它定义了一个 Flexbox 布局环境。
  2. Flex 项目 (Flex Items):

    • Flex 容器的直接子元素。
    • 它们会根据 Flexbox 相关的属性进行布局。
  3. 轴线 (Axes):

    • 主轴 (Main Axis): Flex 项目沿着主轴排列。默认是水平方向(从左到右) 。可以通过 flex-direction 属性改变主轴的方向。
    • 交叉轴 (Cross Axis): 垂直于主轴的轴线。默认是垂直方向(从上到下) 。如果主轴变为垂直,交叉轴就变为水平。

关键的 Flexbox 属性

这些属性分为应用于 Flex 容器 的和应用于 Flex 项目 的。

1. Flex 容器属性 (Container Properties):

  • display:

    • flex: 将元素定义为块级的 Flex 容器。
    • inline-flex: 将元素定义为行内级的 Flex 容器。
  • flex-direction: 定义主轴的方向,从而决定项目排列的方向。

    • row (默认值): 主轴为水平方向,起点在左端。
    • row-reverse: 主轴为水平方向,起点在右端。
    • column: 主轴为垂直方向,起点在上沿。
    • column-reverse: 主轴为垂直方向,起点在下沿。
  • flex-wrap: 定义当一条轴线排不下所有项目时,如何换行。

    • nowrap (默认值): 不换行,项目可能会溢出容器。
    • wrap: 换行,第一行在上方。
    • wrap-reverse: 换行,第一行在下方。
  • flex-flow: flex-direction 和 flex-wrap 的简写形式。

    • 例如: flex-flow: row wrap;
  • justify-content: 定义项目在 主轴 上的对齐方式。

    • flex-start (默认值): 项目向主轴起点对齐。
    • flex-end: 项目向主轴终点对齐。
    • center: 项目在主轴居中对齐。
    • space-between: 两端对齐,项目之间的间隔都相等(首尾项目贴边)。
    • space-around: 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。
    • space-evenly: 所有项目之间的间隔以及项目与边框之间的间隔都完全相等。
  • align-items: 定义项目在 交叉轴 上如何对齐(适用于单行或所有行)。

    • stretch (默认值): 如果项目未设置高度(或宽度,取决于交叉轴方向),将占满整个容器的高度(或宽度)。
    • flex-start: 项目向交叉轴起点对齐。
    • flex-end: 项目向交叉轴终点对齐。
    • center: 项目在交叉轴居中对齐。
    • baseline: 项目根据其内部文字的基线对齐。
  • align-content: 定义**多根轴线(多行/多列)**在 交叉轴 上的对齐方式。仅在项目换行 (flex-wrap: wrap 或 wrap-reverse) 并且交叉轴上有剩余空间时才生效。如果只有一行,此属性无效。

    • stretch (默认值): 轴线占满整个交叉轴。
    • flex-start: 轴线向交叉轴起点对齐。
    • flex-end: 轴线向交叉轴终点对齐。
    • center: 轴线在交叉轴居中对齐。
    • space-between: 轴线两端对齐,之间的间隔相等。
    • space-around: 每根轴线两侧的间隔相等。
  • gap, row-gap, column-gap: 设置 Flex 项目之间的间距。

    • gap: 10px 20px; (row-gap: 10px, column-gap: 20px)
    • gap: 15px; (row-gap 和 column-gap 都是 15px)

2. Flex 项目属性 (Item Properties):

  • order: 定义项目的排列顺序。数值越小,排列越靠前,默认为 0。可以为负数。

    • 例如: order: -1; 会让该项目排在最前面。
  • flex-grow: 定义项目的放大比例。默认为 0,即如果存在剩余空间,也不放大。

    • 如果所有项目的 flex-grow 都为 1,则它们将等分剩余空间。
    • 如果一个项目的 flex-grow 为 2,其他项目都为 1,则前者占据的剩余空间将比其他项多一倍。
  • flex-shrink: 定义项目的缩小比例。默认为 1,即如果空间不足,该项目将缩小。

    • 如果所有项目的 flex-shrink 都为 1,当空间不足时,都将等比例缩小。
    • 如果一个项目的 flex-shrink 为 0,其他项目都为 1,则空间不足时,前者不缩小。
    • 负值无效。
  • flex-basis: 定义在分配多余空间之前,项目占据的主轴空间(项目的基准大小)。

    • 可以是长度值 (px, em, % 等) 或关键字 auto (默认值,项目的大小是其内容的大小) 或 content。
    • 如果设置为 0%,则项目不占据空间,所有空间都将根据 flex-grow 分配。
  • flex: flex-grow, flex-shrink 和 flex-basis 的简写。默认为 0 1 auto。

    • 常见值:

      • flex: auto; (等同于 1 1 auto):会放大也会缩小,基准大小是内容大小。
      • flex: none; (等同于 0 0 auto):既不放大也不缩小,基准大小是内容大小。
      • flex: 1; (等同于 1 1 0%):会放大也会缩小,基准大小为 0。这是让项目等分剩余空间的常用方法。
      • flex: 2; (等同于 2 1 0%)
  • align-self: 允许单个项目有与其他项目不一样的对齐方式,可覆盖 align-items 属性。默认为 auto,表示继承父元素的 align-items 属性。

    • 可选值与 align-items 相同 (stretch, flex-start, flex-end, center, baseline)。

Flexbox 的优势:

  • 强大的对齐能力: 水平、垂直居中变得异常简单。
  • 空间分配灵活: 可以轻松控制项目如何填充可用空间或在空间不足时如何收缩。
  • 顺序无关性: 可以通过 order 属性轻松改变项目的视觉顺序,而不必更改 HTML 结构。
  • 自动处理等高列: 在 row 方向下,默认的 align-items: stretch 可以轻松实现等高列效果。
  • 响应式友好: 非常适合构建响应式布局的组件。

常用场景:

  • 导航栏(水平或垂直)
  • 项目列表(卡片式布局,需要换行)
  • 组件内部元素的对齐(按钮和输入框的对齐)
  • 需要平均分配空间的布局
  • 垂直居中任何元素

Flexbox vs. Grid:

  • Flexbox 主要设计用于一维布局(要么是行,要么是列)。虽然可以换行,但控制力主要在一维方向上。
  • Grid Layout 则设计用于二维布局(同时处理行和列)。

通常,页面级的整体布局可能更适合 Grid,而组件内部或特定区域的一维排列则非常适合 Flexbox。两者可以很好地结合使用。

Flexbox 是现代 CSS 布局的基石之一,强烈建议深入学习和实践!

案例 1

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Flexbox Examples</title>
    <link rel="stylesheet" href="1.css"> 我们将在 style.css 中编写 CSS
</head>
<body>

    <h1>Flexbox 布局示例</h1>

    <!-- 示例 1: 基本水平排列 -->
    <h2>示例 1: 基本水平排列 (默认)</h2>
    <div class="container example1">
        <div class="item item-1">1</div>
        <div class="item item-2">2</div>
        <div class="item item-3">3</div>
    </div>

    <!-- 示例 2: 水平垂直居中 -->
    <h2>示例 2: 水平垂直居中</h2>
    <div class="container example2">
        <div class="item item-1">1</div>
        <div class="item item-2">2</div>
        <div class="item item-3">3</div>
    </div>

    <!-- 示例 3: 改变主轴方向为垂直 -->
    <h2>示例 3: 改变主轴方向为垂直</h2>
    <div class="container example3">
        <div class="item item-1">1</div>
        <div class="item item-2">2</div>
        <div class="item item-3">3</div>
    </div>

     <!-- 示例 4: 项目换行 -->
    <h2>示例 4: 项目换行</h2>
    <div class="container example4">
        <div class="item item-1">1</div>
        <div class="item item-2">2</div>
        <div class="item item-3">3</div>
        <div class="item item-4">4</div>
        <div class="item item-5">5</div>
        <div class="item item-6">6</div>
    </div>

    <!-- 示例 5: 空间分配 (space-between) -->
    <h2>示例 5: 空间分配 (space-between)</h2>
    <div class="container example5">
        <div class="item item-1">1</div>
        <div class="item item-2">2</div>
        <div class="item item-3">3</div>
    </div>

    <!-- 示例 6: 项目弹性增长 (flex-grow) -->
    <h2>示例 6: 项目弹性增长 (flex-grow)</h2>
    <div class="container example6">
        <div class="item item-1 grow-1">1 (flex: 1)</div>
        <div class="item item-2 grow-2">2 (flex: 2)</div>
        <div class="item item-3 grow-1">3 (flex: 1)</div>
    </div>

    <!-- 示例 7: 改变项目顺序 (order) -->
    <h2>示例 7: 改变项目顺序 (order)</h2>
    <div class="container example7">
        <div class="item item-1 order-3">1 (order: 3)</div>
        <div class="item item-2 order-1">2 (order: 1)</div>
        <div class="item item-3 order-2">3 (order: 2)</div>
    </div>

     <!-- 示例 8: 单个项目对齐 (align-self) -->
    <h2>示例 8: 单个项目对齐 (align-self)</h2>
    <div class="container example8">
        <div class="item item-1">1</div>
        <div class="item item-2 self-end">2 (align-self: flex-end)</div>
        <div class="item item-3">3</div>
    </div>

     <!-- 示例 9: 使用间距 (gap) -->
    <h2>示例 9: 使用间距 (gap)</h2>
    <div class="container example9">
        <div class="item item-1">1</div>
        <div class="item item-2">2</div>
        <div class="item item-3">3</div>
        <div class="item item-4">4</div>
        <div class="item item-5">5</div>
    </div>

</body>
</html>
body {
  font-family: sans-serif;
}

.container {
  border: 3px solid steelblue;
  background-color: lightgray;
  padding: 10px;
  margin-bottom: 30px; /* 区分示例 */
  min-height: 150px; /* 给容器一些最小高度,便于观察垂直对齐 */
  display: flex; /* !! 核心:启用 Flexbox !! */
}

.item {
  border: 1px solid #666;
  background-color: lightcoral;
  padding: 20px;
  margin: 5px; /* 给项目一些外边距,便于区分 */
  text-align: center;
  font-size: 1.2em;
  color: white;
  min-width: 50px; /* 确保项目有基本宽度 */
}

/* 为不同项目添加不同颜色(可选,便于区分) */
.item-1 { background-color: #e74c3c; }
.item-2 { background-color: #f1c40f; }
.item-3 { background-color: #2ecc71; }
.item-4 { background-color: #3498db; }
.item-5 { background-color: #9b59b6; }
.item-6 { background-color: #1abc9c; }

/* --- 各示例特定样式 --- */

/* 示例 1: 基本水平排列 (默认) */
/* 无需额外样式,默认就是 flex-direction: row; flex-wrap: nowrap; align-items: stretch; */

/* 示例 2: 水平垂直居中 */
.example2 {
  justify-content: center; /* 主轴(水平)居中 */
  align-items: center;     /* 交叉轴(垂直)居中 */
}

/* 示例 3: 改变主轴方向为垂直 */
.example3 {
  flex-direction: column; /* 主轴变为垂直 */
  align-items: flex-start; /* 交叉轴(现在是水平)起点对齐,防止项目拉伸 */
  /* 注意:此时 justify-content 控制垂直对齐,align-items 控制水平对齐 */
  height: 300px; /* 给个固定高度看效果 */
}
.example3 .item {
  width: 80%; /* 限制宽度,否则默认会水平撑满 */
}


/* 示例 4: 项目换行 */
.example4 {
  flex-wrap: wrap; /* 允许项目换行 */
  /* 可以调整容器宽度来看换行效果 */
  /* width: 350px; */
}

/* 示例 5: 空间分配 (space-between) */
.example5 {
  justify-content: space-between; /* 两端对齐,项目间等间距 */
  /* 试试 space-around 或 space-evenly 看看区别 */
  /* justify-content: space-around; */
  /* justify-content: space-evenly; */
}


/* 示例 6: 项目弹性增长 (flex-grow) */
/* 我们将 flex 属性直接写在 HTML 元素的 style 里,或者像这样定义类 */
.example6 .item {
  flex-shrink: 0; /* 为演示方便,禁止缩小 */
}
.example6 .grow-1 {
  flex-grow: 1; /* 占据 1 份剩余空间 */
  /* 或者简写 flex: 1; (等同于 flex: 1 1 0%) */
}
.example6 .grow-2 {
  flex-grow: 2; /* 占据 2 份剩余空间 */
   /* 或者简写 flex: 2; (等同于 flex: 2 1 0%) */
}


/* 示例 7: 改变项目顺序 (order) */
.example7 .order-1 {
  order: 1;
}
.example7 .order-2 {
  order: 2;
}
.example7 .order-3 {
  order: 3;
}
/* 注意:上面例子中,HTML 结构是 1-2-3,但 order 让它们显示为 2-3-1 */
/* 也可以使用负数,比如 order: -1 让元素排最前 */


/* 示例 8: 单个项目对齐 (align-self) */
.example8 {
  align-items: flex-start; /* 先让所有项目默认靠上对齐 */
  height: 200px; /* 确保有足够垂直空间看效果 */
}
.example8 .self-end {
  align-self: flex-end; /* 单独让这个项目在交叉轴(垂直)底部对齐 */
  /* 试试 align-self: center; 或 stretch; */
}


/* 示例 9: 使用间距 (gap) */
.example9 {
  flex-wrap: wrap; /* 允许换行 */
  gap: 15px; /* 同时设置行间距和列间距为 15px */
  /* 或者分别设置: */
  /* row-gap: 20px; */
  /* column-gap: 10px; */
}
.example9 .item {
  margin: 0; /* 注意:使用 gap 时,通常不再需要给 item 设置 margin */
}

案例 2

<!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>
      .container {
        display: flex;
      }
      .box {
        flex: 1;
        background: lightblue;
        text-align: center;
        padding: 20px;
        margin: 5px;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="box">1</div>
      <div class="box">2</div>
      <div class="box">3</div>
    </div>
  </body>
</html>

案例 3

<!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>
      .container {
        display: flex;
      }
      .left,
      .right {
        width: 100px;
        background: #ddd;
      }
      .center {
        flex: 1;
        background: #eee;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="left"></div>
      <div class="center"></div>
      <div class="right"></div>
    </div>
  </body>
</html>

案例 4

<!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>
      .card-list {
        display: flex;
        flex-wrap: wrap;
        gap: 10px;
      }
      .card {
        flex: 1 1 200px;
        background: lightgreen;
        padding: 20px;
      }
    </style>
  </head>
  <body>
    <div class="card-list">
      <div class="card">卡片1</div>
      <div class="card">卡片2</div>
      <div class="card">卡片3</div>
      <div class="card">卡片4</div>
    </div>
  </body>
</html>