轩辕李的博客 轩辕李的博客
首页
  • Java
  • Spring
  • 其他语言
  • 工具
  • JavaScript
  • TypeScript
  • Node.js
  • Vue.js
  • 前端工程化
  • 浏览器与Web API
  • 分布式
  • 代码质量管理
  • 基础
  • 操作系统
  • 计算机网络
  • 编程范式
  • 安全
  • 中间件
  • 心得
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

轩辕李

勇猛精进,星辰大海
首页
  • Java
  • Spring
  • 其他语言
  • 工具
  • JavaScript
  • TypeScript
  • Node.js
  • Vue.js
  • 前端工程化
  • 浏览器与Web API
  • 分布式
  • 代码质量管理
  • 基础
  • 操作系统
  • 计算机网络
  • 编程范式
  • 安全
  • 中间件
  • 心得
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • JavaScript

  • TypeScript

  • Node.js

  • Vue.js

  • 工程化

  • 浏览器与Web API

    • HTML基础-语义化标签与文档结构
    • HTML基础-文本与排版标签
    • HTML基础-列表与表格
    • HTML表单-Input类型详解
    • HTML表单-表单元素与验证
    • HTML交互-多媒体元素
    • HTML工程化-模板与组件化
    • HTML工程化-性能优化
    • CSS基础-选择器与优先级
    • CSS基础-盒模型与布局基础
    • CSS基础-单位与颜色系统
    • CSS基础-文本与字体
    • CSS基础-背景、列表与表格样式
    • CSS布局-Flexbox完全指南
      • 一、Flexbox 基础概念
        • 1.1 什么是 Flexbox
        • 1.2 核心术语
        • 1.3 基本使用
      • 二、容器属性
        • 2.1 flex-direction (主轴方向)
        • 2.2 flex-wrap (换行)
        • 2.3 flex-flow (简写)
        • 2.4 justify-content (主轴对齐)
        • 2.5 align-items (交叉轴对齐)
        • 2.6 align-content (多行对齐)
        • 2.7 gap (间距)
      • 三、项目属性
        • 3.1 order (排序)
        • 3.2 flex-grow (放大比例)
        • 3.3 flex-shrink (缩小比例)
        • 3.4 flex-basis (基准大小)
        • 3.5 flex (简写)
        • 3.6 align-self (单独对齐)
      • 四、实战案例
        • 4.1 导航栏布局
        • 4.2 卡片网格
        • 4.3 圣杯布局
        • 4.4 等高列布局
        • 4.5 完美居中
        • 4.6 响应式表单
      • 五、常见布局模式
        • 5.1 两列布局(侧边栏固定)
        • 5.2 三列布局(两侧固定)
        • 5.3 自适应网格
        • 5.4 底部固定布局
        • 5.5 粘性页脚
      • 六、最佳实践
        • 6.1 何时使用 Flexbox
        • 6.2 常见技巧
        • 6.3 性能优化
        • 6.4 可访问性
        • 6.5 常见问题解决
      • 七、浏览器兼容性
      • 八、总结
    • CSS布局-Grid网格布局
    • CSS布局-响应式设计实践
    • CSS进阶-动画与过渡
    • CSS进阶-渐变与阴影效果
    • CSS进阶-Transform与3D变换
    • CSS进阶-滤镜与混合模式
    • 现代CSS-CSS预处理器对比
    • 现代CSS-CSS-in-JS方案
    • 现代CSS-原子化CSS与Tailwind
    • CSS工程化-架构与规范
    • CSS工程化-性能优化
    • CSS工程化-PostCSS实战指南
    • Web API基础-DOM操作完全指南
    • Web API基础-事件处理与委托
    • Web API基础-BOM与浏览器环境
    • Web API存储-客户端存储方案
    • Web API网络-HTTP请求详解
    • Web API网络-实时通信方案
    • Web API交互-用户体验增强
    • HTML&CSS历代版本新特性
  • 前端
  • 浏览器与Web API
轩辕李
2019-05-05
目录

CSS布局-Flexbox完全指南

Flexbox(弹性盒子布局)是现代CSS布局的核心技术,它提供了一种更加高效的方式来布局、对齐和分配容器内项目的空间。

本文将全面介绍Flexbox的概念、属性和实战应用,帮助你掌握这一强大的布局工具。

# 一、Flexbox 基础概念

# 1.1 什么是 Flexbox

Flexbox(Flexible Box Layout)是一维布局模型,专门用于在容器内排列项目,即使它们的大小未知或动态变化。

主要特点:

  • 一维布局(沿主轴或交叉轴)
  • 自动分配空间
  • 灵活的对齐方式
  • 响应式布局友好

# 1.2 核心术语

┌─────────────────────────────────────────────┐
│  Flex Container (flex容器)                  │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  │
│  │   Flex   │  │   Flex   │  │   Flex   │  │
│  │   Item   │  │   Item   │  │   Item   │  │  → 交叉轴 (Cross Axis)
│  └──────────┘  └──────────┘  └──────────┘  │
│  ←────────── 主轴 (Main Axis) ───────────→  │
└─────────────────────────────────────────────┘
  • Flex Container(容器):设置了 display: flex 或 display: inline-flex 的元素
  • Flex Item(项目):容器的直接子元素
  • Main Axis(主轴):项目排列的主要方向
  • Cross Axis(交叉轴):垂直于主轴的方向
  • Main Start/End:主轴的起点/终点
  • Cross Start/End:交叉轴的起点/终点

# 1.3 基本使用

.container {
  display: flex; /* 块级flex容器 */
}

.inline-container {
  display: inline-flex; /* 行内flex容器 */
}

# 二、容器属性

# 2.1 flex-direction (主轴方向)

决定主轴的方向,即项目的排列方向。

.container {
  flex-direction: row;            /* 默认值:水平从左到右 */
  flex-direction: row-reverse;    /* 水平从右到左 */
  flex-direction: column;         /* 垂直从上到下 */
  flex-direction: column-reverse; /* 垂直从下到上 */
}
<html>
  <div class="demo-wrapper">
    <div class="demo-section">
      <div class="label">row (默认)</div>
      <div class="container row">
        <div class="item">1</div>
        <div class="item">2</div>
        <div class="item">3</div>
      </div>
    </div>
    
    <div class="demo-section">
      <div class="label">row-reverse</div>
      <div class="container row-reverse">
        <div class="item">1</div>
        <div class="item">2</div>
        <div class="item">3</div>
      </div>
    </div>
    
    <div class="demo-section">
      <div class="label">column</div>
      <div class="container column">
        <div class="item">1</div>
        <div class="item">2</div>
        <div class="item">3</div>
      </div>
    </div>
    
    <div class="demo-section">
      <div class="label">column-reverse</div>
      <div class="container column-reverse">
        <div class="item">1</div>
        <div class="item">2</div>
        <div class="item">3</div>
      </div>
    </div>
  </div>
</html>
<style>
  .demo-wrapper {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 20px;
  }
  
  .demo-section {
    background: #f5f5f5;
    padding: 15px;
    border-radius: 4px;
  }
  
  .label {
    font-weight: bold;
    margin-bottom: 10px;
    color: #333;
  }
  
  .container {
    display: flex;
    background: #e3f2fd;
    padding: 10px;
    border: 2px solid #2196f3;
  }
  
  .row { flex-direction: row; }
  .row-reverse { flex-direction: row-reverse; }
  .column { flex-direction: column; }
  .column-reverse { flex-direction: column-reverse; }
  
  .item {
    background: #2196f3;
    color: white;
    padding: 15px;
    margin: 5px;
    border-radius: 4px;
    font-weight: bold;
    text-align: center;
    min-width: 40px;
  }
</style>

# 2.2 flex-wrap (换行)

决定项目是否换行以及换行方式。

.container {
  flex-wrap: nowrap;       /* 默认值:不换行 */
  flex-wrap: wrap;         /* 换行,第一行在上方 */
  flex-wrap: wrap-reverse; /* 换行,第一行在下方 */
}
<html>
  <div class="wrap-demo">
    <div class="section">
      <div class="label">nowrap (不换行)</div>
      <div class="wrap-container nowrap">
        <div class="wrap-item">1</div>
        <div class="wrap-item">2</div>
        <div class="wrap-item">3</div>
        <div class="wrap-item">4</div>
        <div class="wrap-item">5</div>
        <div class="wrap-item">6</div>
      </div>
    </div>
    
    <div class="section">
      <div class="label">wrap (换行)</div>
      <div class="wrap-container wrap">
        <div class="wrap-item">1</div>
        <div class="wrap-item">2</div>
        <div class="wrap-item">3</div>
        <div class="wrap-item">4</div>
        <div class="wrap-item">5</div>
        <div class="wrap-item">6</div>
      </div>
    </div>
    
    <div class="section">
      <div class="label">wrap-reverse (反向换行)</div>
      <div class="wrap-container wrap-reverse">
        <div class="wrap-item">1</div>
        <div class="wrap-item">2</div>
        <div class="wrap-item">3</div>
        <div class="wrap-item">4</div>
        <div class="wrap-item">5</div>
        <div class="wrap-item">6</div>
      </div>
    </div>
  </div>
</html>
<style>
  .wrap-demo .section {
    margin-bottom: 20px;
  }
  
  .wrap-demo .label {
    font-weight: bold;
    margin-bottom: 10px;
    color: #333;
  }
  
  .wrap-container {
    display: flex;
    background: #e3f2fd;
    padding: 10px;
    border: 2px solid #2196f3;
    max-width: 300px;
  }
  
  .nowrap { flex-wrap: nowrap; }
  .wrap { flex-wrap: wrap; }
  .wrap-reverse { flex-wrap: wrap-reverse; }
  
  .wrap-item {
    background: #2196f3;
    color: white;
    padding: 15px 20px;
    margin: 5px;
    border-radius: 4px;
    font-weight: bold;
  }
</style>

# 2.3 flex-flow (简写)

flex-direction 和 flex-wrap 的简写形式。

.container {
  /* flex-flow: <flex-direction> <flex-wrap> */
  flex-flow: row wrap;
  flex-flow: column nowrap;
  flex-flow: row-reverse wrap;
}

# 2.4 justify-content (主轴对齐)

定义项目在主轴上的对齐方式。

.container {
  justify-content: flex-start;    /* 默认值:起点对齐 */
  justify-content: flex-end;      /* 终点对齐 */
  justify-content: center;        /* 居中对齐 */
  justify-content: space-between; /* 两端对齐,项目间间隔相等 */
  justify-content: space-around;  /* 项目两侧间隔相等 */
  justify-content: space-evenly;  /* 项目间间隔完全相等 */
}
<html>
  <div class="justify-demo">
    <div class="j-section">
      <div class="j-label">flex-start</div>
      <div class="j-container flex-start">
        <div class="j-item">1</div>
        <div class="j-item">2</div>
        <div class="j-item">3</div>
      </div>
    </div>
    
    <div class="j-section">
      <div class="j-label">flex-end</div>
      <div class="j-container flex-end">
        <div class="j-item">1</div>
        <div class="j-item">2</div>
        <div class="j-item">3</div>
      </div>
    </div>
    
    <div class="j-section">
      <div class="j-label">center</div>
      <div class="j-container center">
        <div class="j-item">1</div>
        <div class="j-item">2</div>
        <div class="j-item">3</div>
      </div>
    </div>
    
    <div class="j-section">
      <div class="j-label">space-between</div>
      <div class="j-container space-between">
        <div class="j-item">1</div>
        <div class="j-item">2</div>
        <div class="j-item">3</div>
      </div>
    </div>
    
    <div class="j-section">
      <div class="j-label">space-around</div>
      <div class="j-container space-around">
        <div class="j-item">1</div>
        <div class="j-item">2</div>
        <div class="j-item">3</div>
      </div>
    </div>
    
    <div class="j-section">
      <div class="j-label">space-evenly</div>
      <div class="j-container space-evenly">
        <div class="j-item">1</div>
        <div class="j-item">2</div>
        <div class="j-item">3</div>
      </div>
    </div>
  </div>
</html>
<style>
  .justify-demo .j-section {
    margin-bottom: 15px;
  }
  
  .justify-demo .j-label {
    font-weight: bold;
    margin-bottom: 8px;
    color: #333;
    font-size: 14px;
  }
  
  .j-container {
    display: flex;
    background: #e3f2fd;
    padding: 10px;
    border: 2px solid #2196f3;
  }
  
  .flex-start { justify-content: flex-start; }
  .flex-end { justify-content: flex-end; }
  .center { justify-content: center; }
  .space-between { justify-content: space-between; }
  .space-around { justify-content: space-around; }
  .space-evenly { justify-content: space-evenly; }
  
  .j-item {
    background: #2196f3;
    color: white;
    padding: 10px 15px;
    border-radius: 4px;
    font-weight: bold;
  }
</style>

# 2.5 align-items (交叉轴对齐)

定义项目在交叉轴上的对齐方式。

.container {
  align-items: stretch;     /* 默认值:拉伸填充 */
  align-items: flex-start;  /* 起点对齐 */
  align-items: flex-end;    /* 终点对齐 */
  align-items: center;      /* 居中对齐 */
  align-items: baseline;    /* 基线对齐 */
}
<html>
  <div class="align-demo-a1b2c">
    <div class="a-section-a1b2c">
      <div class="a-label-a1b2c">stretch (默认)</div>
      <div class="a-container-a1b2c stretch-a1b2c">
        <div class="a-item-a1b2c item1-a1b2c">短</div>
        <div class="a-item-a1b2c item2-a1b2c" style="font-size: 20px;">中等<br>内容</div>
        <div class="a-item-a1b2c item3-a1b2c">长内容<br>换行显示</div>
      </div>
    </div>
    
    <div class="a-section-a1b2c">
      <div class="a-label-a1b2c">flex-start</div>
      <div class="a-container-a1b2c a-flex-start-a1b2c">
        <div class="a-item-a1b2c item1-a1b2c">短</div>
        <div class="a-item-a1b2c item2-a1b2c" style="font-size: 20px;">中等<br>内容</div>
        <div class="a-item-a1b2c item3-a1b2c">长内容<br>换行显示</div>
      </div>
    </div>
    
    <div class="a-section-a1b2c">
      <div class="a-label-a1b2c">flex-end</div>
      <div class="a-container-a1b2c a-flex-end-a1b2c">
        <div class="a-item-a1b2c item1-a1b2c">短</div>
        <div class="a-item-a1b2c item2-a1b2c" style="font-size: 20px;">中等<br>内容</div>
        <div class="a-item-a1b2c item3-a1b2c">长内容<br>换行显示</div>
      </div>
    </div>
    
    <div class="a-section-a1b2c">
      <div class="a-label-a1b2c">center</div>
      <div class="a-container-a1b2c a-center-a1b2c">
        <div class="a-item-a1b2c item1-a1b2c">短</div>
        <div class="a-item-a1b2c item2-a1b2c" style="font-size: 20px;">中等<br>内容</div>
        <div class="a-item-a1b2c item3-a1b2c">长内容<br>换行显示</div>
      </div>
    </div>
    
    <div class="a-section-a1b2c">
      <div class="a-label-a1b2c">baseline</div>
      <div class="a-container-a1b2c a-baseline-a1b2c">
        <div class="a-item-a1b2c item1-a1b2c">短</div>
        <div class="a-item-a1b2c item2-a1b2c" style="font-size: 20px;">中等<br>内容</div>
        <div class="a-item-a1b2c item3-a1b2c">长内容<br>换行显示</div>
      </div>
    </div>
  </div>
</html>
<style>
  .align-demo-a1b2c .a-section-a1b2c {
    margin-bottom: 15px;
  }
  
  .align-demo-a1b2c .a-label-a1b2c {
    font-weight: bold;
    margin-bottom: 8px;
    color: #333;
    font-size: 14px;
  }
  
  .a-container-a1b2c {
    display: flex;
    background: #e3f2fd;
    padding: 10px;
    border: 2px solid #2196f3;
    height: 120px;
  }
  
  .stretch-a1b2c { align-items: stretch; }
  .a-flex-start-a1b2c { align-items: flex-start; }
  .a-flex-end-a1b2c { align-items: flex-end; }
  .a-center-a1b2c { align-items: center; }
  .a-baseline-a1b2c { align-items: baseline; }
  
  .a-item-a1b2c {
    padding: 10px 15px;
    border-radius: 4px;
    font-weight: bold;
    margin: 0 5px;
    text-align: center;
  }
  
  .item1-a1b2c {
    background: #2196f3;
    color: white;
  }
  
  .item2-a1b2c {
    background: #ff5722;
    color: white;
  }
  
  .item3-a1b2c {
    background: #4caf50;
    color: white;
  }
  
  .stretch-a1b2c .a-item-a1b2c {
    align-self: stretch;
  }
</style>

# 2.6 align-content (多行对齐)

定义多根轴线的对齐方式(只在多行时生效)。

.container {
  align-content: stretch;       /* 默认值:拉伸填充 */
  align-content: flex-start;    /* 起点对齐 */
  align-content: flex-end;      /* 终点对齐 */
  align-content: center;        /* 居中对齐 */
  align-content: space-between; /* 两端对齐 */
  align-content: space-around;  /* 间隔相等 */
  align-content: space-evenly;  /* 完全平分 */
}
<html>
  <div class="ac-demo-b3h8k">
    <div class="ac-section-b3h8k">
      <div class="ac-label-b3h8k">flex-start (项目靠上)</div>
      <div class="ac-container-b3h8k ac-flex-start-b3h8k">
        <div class="ac-item-b3h8k item1-b3h8k">1</div>
        <div class="ac-item-b3h8k item2-b3h8k">2</div>
        <div class="ac-item-b3h8k item3-b3h8k">3</div>
        <div class="ac-item-b3h8k item4-b3h8k">4</div>
        <div class="ac-item-b3h8k item5-b3h8k">5</div>
        <div class="ac-item-b3h8k item6-b3h8k">6</div>
      </div>
    </div>
    
    <div class="ac-section-b3h8k">
      <div class="ac-label-b3h8k">center (项目居中)</div>
      <div class="ac-container-b3h8k ac-center-b3h8k">
        <div class="ac-item-b3h8k item1-b3h8k">1</div>
        <div class="ac-item-b3h8k item2-b3h8k">2</div>
        <div class="ac-item-b3h8k item3-b3h8k">3</div>
        <div class="ac-item-b3h8k item4-b3h8k">4</div>
        <div class="ac-item-b3h8k item5-b3h8k">5</div>
        <div class="ac-item-b3h8k item6-b3h8k">6</div>
      </div>
    </div>
    
    <div class="ac-section-b3h8k">
      <div class="ac-label-b3h8k">space-between (两端对齐)</div>
      <div class="ac-container-b3h8k ac-space-between-b3h8k">
        <div class="ac-item-b3h8k item1-b3h8k">1</div>
        <div class="ac-item-b3h8k item2-b3h8k">2</div>
        <div class="ac-item-b3h8k item3-b3h8k">3</div>
        <div class="ac-item-b3h8k item4-b3h8k">4</div>
        <div class="ac-item-b3h8k item5-b3h8k">5</div>
        <div class="ac-item-b3h8k item6-b3h8k">6</div>
      </div>
    </div>
    
    <div class="ac-section-b3h8k">
      <div class="ac-label-b3h8k">stretch (拉伸填充)</div>
      <div class="ac-container-b3h8k ac-stretch-b3h8k">
        <div class="ac-item-b3h8k item1-b3h8k">1</div>
        <div class="ac-item-b3h8k item2-b3h8k">2</div>
        <div class="ac-item-b3h8k item3-b3h8k">3</div>
        <div class="ac-item-b3h8k item4-b3h8k">4</div>
        <div class="ac-item-b3h8k item5-b3h8k">5</div>
        <div class="ac-item-b3h8k item6-b3h8k">6</div>
      </div>
    </div>
  </div>
</html>
<style>
  .ac-demo-b3h8k .ac-section-b3h8k {
    margin-bottom: 20px;
  }
  
  .ac-demo-b3h8k .ac-label-b3h8k {
    font-weight: bold;
    margin-bottom: 8px;
    color: #333;
    font-size: 14px;
  }
  
  .ac-container-b3h8k {
    display: flex;
    flex-wrap: wrap;
    background: #e3f2fd;
    padding: 10px;
    border: 2px solid #2196f3;
    height: 180px;
    width: 280px;
  }
  
  .ac-flex-start-b3h8k { align-content: flex-start; }
  .ac-center-b3h8k { align-content: center; }
  .ac-space-between-b3h8k { align-content: space-between; }
  .ac-stretch-b3h8k { align-content: stretch; }
  
  .ac-item-b3h8k {
    padding: 10px 15px;
    border-radius: 4px;
    font-weight: bold;
    margin: 3px;
    text-align: center;
    min-width: 40px;
  }
  
  .item1-b3h8k, .item4-b3h8k {
    background: #2196f3;
    color: white;
  }
  
  .item2-b3h8k, .item5-b3h8k {
    background: #ff5722;
    color: white;
  }
  
  .item3-b3h8k, .item6-b3h8k {
    background: #4caf50;
    color: white;
  }
</style>

# 2.7 gap (间距)

设置项目之间的间距(现代CSS)。

.container {
  gap: 20px;           /* 行列间距相同 */
  gap: 10px 20px;      /* 行间距 列间距 */
  row-gap: 10px;       /* 只设置行间距 */
  column-gap: 20px;    /* 只设置列间距 */
}
<html>
  <div class="gap-demo-c4j9m">
    <div class="gap-section-c4j9m">
      <div class="gap-label-c4j9m">无gap</div>
      <div class="gap-container-c4j9m">
        <div class="gap-item-c4j9m">1</div>
        <div class="gap-item-c4j9m">2</div>
        <div class="gap-item-c4j9m">3</div>
        <div class="gap-item-c4j9m">4</div>
      </div>
    </div>
    
    <div class="gap-section-c4j9m">
      <div class="gap-label-c4j9m">gap: 10px</div>
      <div class="gap-container-c4j9m gap-10-c4j9m">
        <div class="gap-item-c4j9m">1</div>
        <div class="gap-item-c4j9m">2</div>
        <div class="gap-item-c4j9m">3</div>
        <div class="gap-item-c4j9m">4</div>
      </div>
    </div>
    
    <div class="gap-section-c4j9m">
      <div class="gap-label-c4j9m">gap: 5px 20px</div>
      <div class="gap-container-c4j9m gap-custom-c4j9m">
        <div class="gap-item-c4j9m">1</div>
        <div class="gap-item-c4j9m">2</div>
        <div class="gap-item-c4j9m">3</div>
        <div class="gap-item-c4j9m">4</div>
      </div>
    </div>
  </div>
</html>
<style>
  .gap-demo-c4j9m .gap-section-c4j9m {
    margin-bottom: 15px;
  }
  
  .gap-demo-c4j9m .gap-label-c4j9m {
    font-weight: bold;
    margin-bottom: 8px;
    color: #333;
    font-size: 14px;
  }
  
  .gap-container-c4j9m {
    display: flex;
    flex-wrap: wrap;
    background: #e3f2fd;
    padding: 10px;
    border: 2px solid #2196f3;
    width: 200px;
  }
  
  .gap-10-c4j9m { gap: 10px; }
  .gap-custom-c4j9m { gap: 5px 20px; }
  
  .gap-item-c4j9m {
    background: #2196f3;
    color: white;
    padding: 10px 15px;
    border-radius: 4px;
    font-weight: bold;
  }
</style>

# 三、项目属性

# 3.1 order (排序)

定义项目的排列顺序,数值越小越靠前。

.item {
  order: 0;  /* 默认值 */
  order: 1;  /* 数值越小,排列越靠前 */
  order: -1; /* 可以为负数 */
}
<html>
  <div class="order-container">
    <div class="order-item" style="order: 3;">order: 3</div>
    <div class="order-item" style="order: 1;">order: 1</div>
    <div class="order-item" style="order: 4;">order: 4</div>
    <div class="order-item" style="order: 2;">order: 2</div>
  </div>
</html>
<style>
  .order-container {
    display: flex;
    background: #e3f2fd;
    padding: 15px;
    border: 2px solid #2196f3;
    gap: 10px;
  }
  
  .order-item {
    background: #2196f3;
    color: white;
    padding: 15px 20px;
    border-radius: 4px;
    font-weight: bold;
  }
</style>

# 3.2 flex-grow (放大比例)

定义项目的放大比例,决定如何分配剩余空间。

.item {
  flex-grow: 0; /* 默认值:不放大 */
  flex-grow: 1; /* 等比例放大 */
  flex-grow: 2; /* 放大比例为其他项目的2倍 */
}
<html>
  <div class="grow-container">
    <div class="grow-item" style="flex-grow: 1;">flex-grow: 1</div>
    <div class="grow-item" style="flex-grow: 2;">flex-grow: 2</div>
    <div class="grow-item" style="flex-grow: 1;">flex-grow: 1</div>
  </div>
</html>
<style>
  .grow-container {
    display: flex;
    background: #e3f2fd;
    padding: 15px;
    border: 2px solid #2196f3;
    gap: 10px;
  }
  
  .grow-item {
    background: #2196f3;
    color: white;
    padding: 15px;
    border-radius: 4px;
    font-weight: bold;
    text-align: center;
  }
</style>

# 3.3 flex-shrink (缩小比例)

定义项目的缩小比例,空间不足时如何缩小。

.item {
  flex-shrink: 1; /* 默认值:等比例缩小 */
  flex-shrink: 0; /* 不缩小 */
  flex-shrink: 2; /* 缩小比例为其他项目的2倍 */
}
<html>
  <div class="shrink-demo-d5k2p">
    <div class="shrink-label-d5k2p">容器宽度 300px,3个项目总宽400px,空间不足</div>
    <div class="shrink-container-d5k2p">
      <div class="shrink-item-d5k2p shrink-1-d5k2p">shrink: 1<br>(100px)</div>
      <div class="shrink-item-d5k2p shrink-0-d5k2p">shrink: 0<br>(200px 不缩)</div>
      <div class="shrink-item-d5k2p shrink-2-d5k2p">shrink: 2<br>(100px)</div>
    </div>
    <div class="shrink-tip-d5k2p">提示:flex-shrink: 0 的项目保持原始大小,其他项目按比例缩小</div>
  </div>
</html>
<style>
  .shrink-demo-d5k2p {
    padding: 15px;
    background: #f5f5f5;
  }
  
  .shrink-label-d5k2p {
    font-weight: bold;
    margin-bottom: 10px;
    color: #333;
    font-size: 14px;
  }
  
  .shrink-container-d5k2p {
    display: flex;
    background: #e3f2fd;
    padding: 10px;
    border: 2px solid #2196f3;
    width: 300px;
  }
  
  .shrink-item-d5k2p {
    background: #2196f3;
    color: white;
    padding: 15px;
    border-radius: 4px;
    font-weight: bold;
    text-align: center;
    font-size: 12px;
    margin: 0 3px;
  }
  
  .shrink-1-d5k2p {
    flex-shrink: 1;
    flex-basis: 100px;
  }
  
  .shrink-0-d5k2p {
    flex-shrink: 0;
    flex-basis: 200px;
    background: #ff5722;
  }
  
  .shrink-2-d5k2p {
    flex-shrink: 2;
    flex-basis: 100px;
  }
  
  .shrink-tip-d5k2p {
    margin-top: 10px;
    padding: 10px;
    background: #fff3cd;
    border-left: 3px solid #ffc107;
    font-size: 13px;
  }
</style>

# 3.4 flex-basis (基准大小)

定义项目在分配多余空间之前的基准大小。

.item {
  flex-basis: auto;   /* 默认值:项目本来大小 */
  flex-basis: 200px;  /* 固定像素值 */
  flex-basis: 30%;    /* 百分比 */
  flex-basis: 0;      /* 忽略项目本身大小 */
}
<html>
  <div class="basis-demo-e6m3q">
    <div class="basis-section-e6m3q">
      <div class="basis-label-e6m3q">flex-basis: auto (根据内容)</div>
      <div class="basis-container-e6m3q">
        <div class="basis-item-e6m3q basis-auto-e6m3q">短</div>
        <div class="basis-item-e6m3q basis-auto-e6m3q">中等内容</div>
        <div class="basis-item-e6m3q basis-auto-e6m3q">较长的内容文字</div>
      </div>
    </div>
    
    <div class="basis-section-e6m3q">
      <div class="basis-label-e6m3q">flex-basis: 100px (固定大小)</div>
      <div class="basis-container-e6m3q">
        <div class="basis-item-e6m3q basis-100-e6m3q">1</div>
        <div class="basis-item-e6m3q basis-100-e6m3q">2</div>
        <div class="basis-item-e6m3q basis-100-e6m3q">3</div>
      </div>
    </div>
    
    <div class="basis-section-e6m3q">
      <div class="basis-label-e6m3q">flex-basis: 0 + flex-grow: 1 (平均分配)</div>
      <div class="basis-container-e6m3q">
        <div class="basis-item-e6m3q basis-0-e6m3q">短</div>
        <div class="basis-item-e6m3q basis-0-e6m3q">中等</div>
        <div class="basis-item-e6m3q basis-0-e6m3q">较长内容</div>
      </div>
    </div>
  </div>
</html>
<style>
  .basis-demo-e6m3q .basis-section-e6m3q {
    margin-bottom: 15px;
  }
  
  .basis-demo-e6m3q .basis-label-e6m3q {
    font-weight: bold;
    margin-bottom: 8px;
    color: #333;
    font-size: 14px;
  }
  
  .basis-container-e6m3q {
    display: flex;
    background: #e3f2fd;
    padding: 10px;
    border: 2px solid #2196f3;
  }
  
  .basis-item-e6m3q {
    background: #2196f3;
    color: white;
    padding: 10px;
    border-radius: 4px;
    font-weight: bold;
    text-align: center;
    margin: 0 5px;
  }
  
  .basis-auto-e6m3q {
    flex-basis: auto;
  }
  
  .basis-100-e6m3q {
    flex-basis: 100px;
  }
  
  .basis-0-e6m3q {
    flex-basis: 0;
    flex-grow: 1;
  }
</style>

# 3.5 flex (简写)

flex-grow、flex-shrink 和 flex-basis 的简写。

.item {
  flex: 1;              /* 等价于 flex: 1 1 0% */
  flex: auto;           /* 等价于 flex: 1 1 auto */
  flex: none;           /* 等价于 flex: 0 0 auto */
  flex: 0 1 200px;      /* flex-grow flex-shrink flex-basis */
}

推荐使用简写:

/* 常用值 */
.item {
  flex: 1;     /* 平均分配空间 */
  flex: 0 0 auto; /* 固定大小,不放大不缩小 */
  flex: 1 0 auto; /* 可放大,不缩小 */
}

# 3.6 align-self (单独对齐)

允许单个项目有与其他项目不同的对齐方式。

.item {
  align-self: auto;       /* 默认值:继承父元素的align-items */
  align-self: flex-start;
  align-self: flex-end;
  align-self: center;
  align-self: baseline;
  align-self: stretch;
}
<html>
  <div class="self-container">
    <div class="self-item">normal</div>
    <div class="self-item" style="align-self: flex-start;">flex-start</div>
    <div class="self-item" style="align-self: center;">center</div>
    <div class="self-item" style="align-self: flex-end;">flex-end</div>
    <div class="self-item">normal</div>
  </div>
</html>
<style>
  .self-container {
    display: flex;
    align-items: stretch;
    background: #e3f2fd;
    padding: 15px;
    border: 2px solid #2196f3;
    height: 120px;
    gap: 10px;
  }
  
  .self-item {
    background: #2196f3;
    color: white;
    padding: 10px 15px;
    border-radius: 4px;
    font-weight: bold;
    font-size: 12px;
  }
</style>

# 四、实战案例

# 4.1 导航栏布局

<html>
  <div class="demo-a7k3m">
    <nav class="navbar-a7k3m">
      <div class="nav-brand-a7k3m">Logo</div>
      <ul class="nav-menu-a7k3m">
        <li class="nav-item-a7k3m"><a href="#" class="nav-link-a7k3m">首页</a></li>
        <li class="nav-item-a7k3m"><a href="#" class="nav-link-a7k3m">产品</a></li>
        <li class="nav-item-a7k3m"><a href="#" class="nav-link-a7k3m">关于</a></li>
      </ul>
      <div class="nav-actions-a7k3m">
        <button class="btn-login-a7k3m">登录</button>
        <button class="btn-signup-a7k3m">注册</button>
      </div>
    </nav>
  </div>
</html>
<style>
  .demo-a7k3m {
    width: 100%;
  }
  
  .navbar-a7k3m {
    display: flex;
    align-items: center;
    justify-content: space-between;
    background: #333;
    color: white;
    padding: 15px 30px;
  }
  
  .nav-brand-a7k3m {
    font-size: 20px;
    font-weight: bold;
  }
  
  .nav-menu-a7k3m {
    display: flex;
    list-style: none;
    margin: 0;
    padding: 0;
    gap: 20px;
    flex: 1;
    justify-content: center;
  }
  
  .nav-item-a7k3m {
    display: inline;
  }
  
  .nav-link-a7k3m {
    color: white;
    text-decoration: none;
    padding: 8px 12px;
    border-radius: 4px;
    transition: background 0.3s;
    display: inline-block;
  }
  
  .nav-link-a7k3m:hover {
    background: rgba(255,255,255,0.1);
  }
  
  .nav-actions-a7k3m {
    display: flex;
    gap: 10px;
  }
  
  .btn-login-a7k3m,
  .btn-signup-a7k3m {
    padding: 8px 16px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    font-weight: bold;
  }
  
  .btn-login-a7k3m {
    background: transparent;
    color: white;
    border: 1px solid white;
  }
  
  .btn-login-a7k3m:hover {
    background: rgba(255,255,255,0.1);
  }
  
  .btn-signup-a7k3m {
    background: #2196f3;
    color: white;
  }
  
  .btn-signup-a7k3m:hover {
    background: #1976d2;
  }
</style>

# 4.2 卡片网格

<html>
  <div class="card-grid">
    <div class="grid-card">
      <div class="card-icon">📱</div>
      <h3>响应式设计</h3>
      <p>适配各种设备</p>
    </div>
    <div class="grid-card">
      <div class="card-icon">⚡</div>
      <h3>高性能</h3>
      <p>优化加载速度</p>
    </div>
    <div class="grid-card">
      <div class="card-icon">🎨</div>
      <h3>美观UI</h3>
      <p>精美的界面设计</p>
    </div>
    <div class="grid-card">
      <div class="card-icon">🔒</div>
      <h3>安全可靠</h3>
      <p>数据加密保护</p>
    </div>
  </div>
</html>
<style>
  .card-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 20px;
  }
  
  .grid-card {
    flex: 1 1 200px;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 30px;
    background: white;
    border: 1px solid #ddd;
    border-radius: 8px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    transition: transform 0.3s, box-shadow 0.3s;
  }
  
  .grid-card:hover {
    transform: translateY(-5px);
    box-shadow: 0 4px 16px rgba(0,0,0,0.15);
  }
  
  .card-icon {
    font-size: 48px;
    margin-bottom: 15px;
  }
  
  .grid-card h3 {
    margin: 0 0 10px 0;
    font-size: 18px;
  }
  
  .grid-card p {
    margin: 0;
    color: #666;
    text-align: center;
    font-size: 14px;
  }
</style>

# 4.3 圣杯布局

<html>
  <div class="holy-grail">
    <header class="hg-header">Header</header>
    <div class="hg-body">
      <aside class="hg-sidebar hg-left">Left Sidebar</aside>
      <main class="hg-main">Main Content</main>
      <aside class="hg-sidebar hg-right">Right Sidebar</aside>
    </div>
    <footer class="hg-footer">Footer</footer>
  </div>
</html>
<style>
  .holy-grail {
    display: flex;
    flex-direction: column;
    min-height: 300px;
    border: 2px solid #ddd;
  }
  
  .hg-header, .hg-footer {
    background: #333;
    color: white;
    padding: 20px;
    text-align: center;
    font-weight: bold;
  }
  
  .hg-body {
    display: flex;
    flex: 1;
  }
  
  .hg-sidebar {
    background: #f5f5f5;
    padding: 20px;
    width: 150px;
  }
  
  .hg-left {
    order: -1;
  }
  
  .hg-main {
    flex: 1;
    background: white;
    padding: 20px;
  }
</style>

# 4.4 等高列布局

<html>
  <div class="equal-height">
    <div class="eh-column">
      <h3>短内容</h3>
      <p>这是较短的内容。</p>
    </div>
    <div class="eh-column">
      <h3>中等内容</h3>
      <p>这是中等长度的内容。Flexbox会自动让所有列等高,无论内容多少。</p>
    </div>
    <div class="eh-column">
      <h3>长内容</h3>
      <p>这是较长的内容。Flexbox的强大之处在于可以轻松实现等高布局,而不需要JavaScript或其他技巧。所有列会自动拉伸到最高列的高度。</p>
    </div>
  </div>
</html>
<style>
  .equal-height {
    display: flex;
    gap: 20px;
  }
  
  .eh-column {
    flex: 1;
    background: #e3f2fd;
    padding: 20px;
    border: 2px solid #2196f3;
    border-radius: 4px;
  }
  
  .eh-column h3 {
    margin: 0 0 15px 0;
    color: #1976d2;
  }
  
  .eh-column p {
    margin: 0;
    line-height: 1.6;
  }
</style>

# 4.5 完美居中

<html>
  <div class="perfect-center">
    <div class="centered-box">
      <h3>完美居中</h3>
      <p>水平和垂直都居中</p>
    </div>
  </div>
</html>
<style>
  .perfect-center {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 200px;
    background: #f5f5f5;
    border: 2px dashed #999;
  }
  
  .centered-box {
    background: #2196f3;
    color: white;
    padding: 30px;
    border-radius: 8px;
    text-align: center;
  }
  
  .centered-box h3 {
    margin: 0 0 10px 0;
  }
  
  .centered-box p {
    margin: 0;
  }
</style>

# 4.6 响应式表单

<html>
  <form class="responsive-form">
    <div class="form-row">
      <div class="form-group">
        <label>姓名</label>
        <input type="text" placeholder="请输入姓名">
      </div>
      <div class="form-group">
        <label>邮箱</label>
        <input type="email" placeholder="请输入邮箱">
      </div>
    </div>
    <div class="form-row">
      <div class="form-group">
        <label>电话</label>
        <input type="tel" placeholder="请输入电话">
      </div>
      <div class="form-group">
        <label>城市</label>
        <input type="text" placeholder="请输入城市">
      </div>
    </div>
    <div class="form-actions">
      <button type="button" class="btn-cancel">取消</button>
      <button type="submit" class="btn-submit">提交</button>
    </div>
  </form>
</html>
<style>
  .responsive-form {
    background: white;
    padding: 20px;
    border: 1px solid #ddd;
    border-radius: 8px;
  }
  
  .form-row {
    display: flex;
    gap: 15px;
    margin-bottom: 15px;
  }
  
  .form-group {
    flex: 1;
    display: flex;
    flex-direction: column;
  }
  
  .form-group label {
    margin-bottom: 5px;
    font-weight: bold;
    font-size: 14px;
    color: #333;
  }
  
  .form-group input {
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 4px;
    font-size: 14px;
  }
  
  .form-actions {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    margin-top: 20px;
  }
  
  .btn-cancel, .btn-submit {
    padding: 10px 20px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    font-weight: bold;
  }
  
  .btn-cancel {
    background: #f5f5f5;
    color: #333;
  }
  
  .btn-submit {
    background: #2196f3;
    color: white;
  }
</style>

# 五、常见布局模式

# 5.1 两列布局(侧边栏固定)

<html>
  <div class="two-col-f7n4r">
    <aside class="sidebar-f7n4r">Sidebar<br>(250px)</aside>
    <main class="main-f7n4r">Main Content<br>(自动填充剩余空间)</main>
  </div>
</html>
<style>
  .two-col-f7n4r {
    display: flex;
    min-height: 200px;
    border: 2px solid #ddd;
  }
  
  .sidebar-f7n4r {
    width: 150px;
    flex-shrink: 0;
    background: #f5f5f5;
    padding: 20px;
    border-right: 2px solid #ddd;
  }
  
  .main-f7n4r {
    flex: 1;
    background: white;
    padding: 20px;
  }
</style>

# 5.2 三列布局(两侧固定)

<html>
  <div class="three-col-g8p5s">
    <aside class="left-sidebar-g8p5s">Left<br>(120px)</aside>
    <main class="main-g8p5s">Main Content<br>(自动填充)</main>
    <aside class="right-sidebar-g8p5s">Right<br>(150px)</aside>
  </div>
</html>
<style>
  .three-col-g8p5s {
    display: flex;
    min-height: 180px;
    border: 2px solid #ddd;
  }
  
  .left-sidebar-g8p5s {
    width: 120px;
    flex-shrink: 0;
    background: #e3f2fd;
    padding: 15px;
    border-right: 2px solid #ddd;
    text-align: center;
  }
  
  .main-g8p5s {
    flex: 1;
    background: white;
    padding: 20px;
    text-align: center;
  }
  
  .right-sidebar-g8p5s {
    width: 150px;
    flex-shrink: 0;
    background: #fff3e0;
    padding: 15px;
    border-left: 2px solid #ddd;
    text-align: center;
  }
</style>

# 5.3 自适应网格

<html>
  <div class="adaptive-grid-h9q6t">
    <div class="grid-item-h9q6t">Item 1</div>
    <div class="grid-item-h9q6t">Item 2</div>
    <div class="grid-item-h9q6t">Item 3</div>
    <div class="grid-item-h9q6t">Item 4</div>
    <div class="grid-item-h9q6t">Item 5</div>
  </div>
  <div class="grid-tip-h9q6t">提示:调整窗口宽度,项目会自动换行</div>
</html>
<style>
  .adaptive-grid-h9q6t {
    display: flex;
    flex-wrap: wrap;
    gap: 15px;
    padding: 15px;
    background: #f5f5f5;
    border: 2px solid #ddd;
  }
  
  .grid-item-h9q6t {
    flex: 1 1 150px;
    min-height: 80px;
    background: #2196f3;
    color: white;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 4px;
    font-weight: bold;
  }
  
  .grid-tip-h9q6t {
    margin-top: 10px;
    padding: 10px;
    background: #fff3cd;
    border-left: 3px solid #ffc107;
    font-size: 13px;
  }
</style>

# 5.4 底部固定布局

<html>
  <div class="sticky-footer-i1r7u">
    <header class="header-i1r7u">Header</header>
    <main class="main-i1r7u">
      Main Content<br>
      (自动填充剩余空间)<br>
      无论内容多少,Footer都在底部
    </main>
    <footer class="footer-i1r7u">Footer</footer>
  </div>
</html>
<style>
  .sticky-footer-i1r7u {
    display: flex;
    flex-direction: column;
    min-height: 300px;
    border: 2px solid #ddd;
  }
  
  .header-i1r7u {
    background: #333;
    color: white;
    padding: 15px;
    text-align: center;
    font-weight: bold;
  }
  
  .main-i1r7u {
    flex: 1;
    background: white;
    padding: 20px;
    text-align: center;
  }
  
  .footer-i1r7u {
    background: #333;
    color: white;
    padding: 15px;
    text-align: center;
    font-weight: bold;
  }
</style>

# 5.5 粘性页脚

<html>
  <div class="sticky-page-j2s8v">
    <header class="page-header-j2s8v">Page Header</header>
    <main class="page-main-j2s8v">
      Page Content<br><br>
      即使内容很少,<br>
      Footer也会粘在底部
    </main>
    <footer class="page-footer-j2s8v">Sticky Footer</footer>
  </div>
</html>
<style>
  .sticky-page-j2s8v {
    display: flex;
    flex-direction: column;
    min-height: 250px;
    border: 2px solid #ddd;
  }
  
  .page-header-j2s8v {
    background: #2196f3;
    color: white;
    padding: 15px;
    text-align: center;
    font-weight: bold;
  }
  
  .page-main-j2s8v {
    flex: 1;
    background: #f5f5f5;
    padding: 20px;
    text-align: center;
  }
  
  .page-footer-j2s8v {
    background: #333;
    color: white;
    padding: 12px;
    text-align: center;
    font-weight: bold;
  }
</style>

# 六、最佳实践

# 6.1 何时使用 Flexbox

✅ 适合使用 Flexbox:

  • 一维布局(行或列)
  • 导航栏、菜单
  • 表单布局
  • 卡片布局
  • 对齐和居中
  • 等高列

❌ 不适合使用 Flexbox:

  • 复杂的二维布局(使用 Grid)
  • 大型页面布局(使用 Grid)

# 6.2 常见技巧

/* 最后一个元素靠右 */
.container {
  display: flex;
}

.item:last-child {
  margin-left: auto;
}

/* 垂直水平完美居中 */
.container {
  display: flex;
  justify-content: center;
  align-items: center;
}

/* 间距使用 gap 而非 margin */
.container {
  display: flex;
  gap: 20px; /* 推荐 */
}

/* 响应式换行 */
.container {
  display: flex;
  flex-wrap: wrap;
}

.item {
  flex: 1 1 300px; /* 最小300px自动换行 */
}

# 6.3 性能优化

/* ✅ 推荐:使用 flex 简写 */
.item {
  flex: 1;
}

/* ❌ 不推荐:分开写 */
.item {
  flex-grow: 1;
  flex-shrink: 1;
  flex-basis: 0%;
}

/* 避免过度嵌套 */
/* ❌ 不推荐 */
.container .row .col .item { }

/* ✅ 推荐 */
.item { }

# 6.4 可访问性

/* 注意:flex order 会影响屏幕阅读器 */
/* 确保视觉顺序和DOM顺序一致 */

/* 如果必须使用 order */
.item {
  order: 2;
}

/* 确保键盘导航仍然正常 */

# 6.5 常见问题解决

问题1:项目溢出容器

/* 解决方案 */
.container {
  min-width: 0; /* 重置最小宽度 */
}

.item {
  overflow: hidden; /* 或 overflow: auto */
}

问题2:项目不等宽

/* 解决方案 */
.item {
  flex: 1 1 0%; /* 而不是 flex: 1 1 auto */
}

问题3:垂直居中无效

/* 确保容器有高度 */
.container {
  display: flex;
  align-items: center;
  min-height: 300px; /* 必须有高度 */
}

# 七、浏览器兼容性

特性 Chrome Firefox Safari Edge IE
基础Flexbox ✅ 29+ ✅ 28+ ✅ 9+ ✅ 12+ ⚠️ 11 (部分)
gap ✅ 84+ ✅ 63+ ✅ 14.1+ ✅ 84+ ❌
flex简写 ✅ ✅ ✅ ✅ ⚠️ 11 (有bug)

兼容性注意事项:

  • IE10-11 需要 -ms- 前缀
  • IE11 的 flex-basis 有bug,避免使用 auto
  • 使用 Autoprefixer 自动添加前缀
  • gap 属性需要较新浏览器,旧浏览器用 margin
/* Autoprefixer 会自动添加前缀 */
.container {
  display: flex;
  /* 编译后会添加:
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  */
}

# 八、总结

Flexbox是现代CSS布局的核心工具,掌握以下要点:

  1. 核心概念:理解主轴、交叉轴、容器和项目
  2. 容器属性:flex-direction、justify-content、align-items 是最常用的
  3. 项目属性:flex 简写最实用,理解 flex-grow、flex-shrink、flex-basis
  4. 实战应用:导航栏、卡片网格、圣杯布局、完美居中
  5. 最佳实践:合理使用,注意性能和可访问性
  6. 兼容性:现代浏览器支持良好,注意IE11的bug

灵活运用Flexbox,能让你的布局代码更简洁、更优雅、更易维护!

祝你变得更强!

编辑 (opens new window)
#CSS
上次更新: 2025/11/20
CSS基础-背景、列表与表格样式
CSS布局-Grid网格布局

← CSS基础-背景、列表与表格样式 CSS布局-Grid网格布局→

最近更新
01
AI编程时代的一些心得
09-11
02
Claude Code与Codex的协同工作
09-01
03
Claude Code 最佳实践(个人版)
08-01
更多文章>
Theme by Vdoing | Copyright © 2018-2025 京ICP备2021021832号-2 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式