Skip to content

Flexbox 布局

Flexbox(弹性盒子布局)是 CSS3 中的一种一维布局模型,它提供了一种更加高效的方式来布置、对齐和分配容器中项目之间的空间,即使它们的大小是未知或动态的。

什么是 Flexbox?

Flexbox 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。任何一个容器都可以指定为 Flex 布局。

基本概念

Flex 容器(Flex Container)

通过设置 display: flexdisplay: inline-flex 创建的容器:

css
.flex-container {
  display: flex; /* 或 inline-flex */
}

Flex 项目(Flex Items)

Flex 容器的直接子元素称为 Flex 项目:

html
<div class="flex-container">
  <div class="flex-item">项目1</div>
  <div class="flex-item">项目2</div>
  <div class="flex-item">项目3</div>
</div>

主轴和交叉轴

  • 主轴(Main Axis):Flex 项目沿其排列的轴线
  • 交叉轴(Cross Axis):垂直于主轴的轴线

Flex 容器属性

flex-direction

决定主轴的方向(项目的排列方向):

css
.flex-container {
  display: flex;
  flex-direction: row; /* 默认值:水平排列 */
}

.flex-container-column {
  display: flex;
  flex-direction: column; /* 垂直排列 */
}

.flex-container-row-reverse {
  display: flex;
  flex-direction: row-reverse; /* 水平反向排列 */
}

.flex-container-column-reverse {
  display: flex;
  flex-direction: column-reverse; /* 垂直反向排列 */
}

flex-wrap

决定项目是否换行:

css
.flex-container-nowrap {
  display: flex;
  flex-wrap: nowrap; /* 默认值:不换行 */
}

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

.flex-container-wrap-reverse {
  display: flex;
  flex-wrap: wrap-reverse; /* 反向换行 */
}

flex-flow

flex-directionflex-wrap 的简写:

css
.flex-container {
  display: flex;
  flex-flow: row wrap; /* 等同于 flex-direction: row; flex-wrap: wrap; */
}

justify-content

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

css
.flex-container-flex-start {
  display: flex;
  justify-content: flex-start; /* 默认值:左对齐 */
}

.flex-container-flex-end {
  display: flex;
  justify-content: flex-end; /* 右对齐 */
}

.flex-container-center {
  display: flex;
  justify-content: center; /* 居中 */
}

.flex-container-space-between {
  display: flex;
  justify-content: space-between; /* 两端对齐,项目之间间隔相等 */
}

.flex-container-space-around {
  display: flex;
  justify-content: space-around; /* 每个项目两侧间隔相等 */
}

.flex-container-space-evenly {
  display: flex;
  justify-content: space-evenly; /* 每个项目周围间隔相等 */
}

align-items

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

css
.flex-container-stretch {
  display: flex;
  align-items: stretch; /* 默认值:拉伸 */
}

.flex-container-flex-start {
  display: flex;
  align-items: flex-start; /* 起点对齐 */
}

.flex-container-flex-end {
  display: flex;
  align-items: flex-end; /* 终点对齐 */
}

.flex-container-center {
  display: flex;
  align-items: center; /* 居中对齐 */
}

.flex-container-baseline {
  display: flex;
  align-items: baseline; /* 基线对齐 */
}

align-content

定义多行项目在交叉轴上的对齐方式(仅在换行时有效):

css
.flex-container-flex-start {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
}

.flex-container-flex-end {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-end;
}

.flex-container-center {
  display: flex;
  flex-wrap: wrap;
  align-content: center;
}

.flex-container-space-between {
  display: flex;
  flex-wrap: wrap;
  align-content: space-between;
}

.flex-container-space-around {
  display: flex;
  flex-wrap: wrap;
  align-content: space-around;
}

.flex-container-stretch {
  display: flex;
  flex-wrap: wrap;
  align-content: stretch;
}

Flex 项目属性

order

定义项目的排列顺序,数值越小排列越靠前,默认为 0:

css
.flex-item {
  order: 1; /* 数值可以是负数 */
}

.flex-item-first {
  order: -1;
}

flex-grow

定义项目的放大比例,默认为 0,即如果存在剩余空间也不放大:

css
.flex-item {
  flex-grow: 1; /* 等分剩余空间 */
}

.flex-item-double {
  flex-grow: 2; /* 占据两倍的剩余空间 */
}

flex-shrink

定义项目的缩小比例,默认为 1,即如果空间不足该项目将缩小:

css
.flex-item {
  flex-shrink: 1; /* 空间不足时缩小 */
}

.flex-item-no-shrink {
  flex-shrink: 0; /* 空间不足时不缩小 */
}

flex-basis

定义在分配多余空间之前,项目占据的主轴空间(main size):

css
.flex-item {
  flex-basis: auto; /* 默认值,项目本来的大小 */
}

.flex-item-fixed {
  flex-basis: 200px; /* 固定大小 */
}

.flex-item-percent {
  flex-basis: 30%; /* 百分比 */
}

flex

flex-grow, flex-shrinkflex-basis 的简写,默认值为 0 1 auto

css
.flex-item {
  flex: 1; /* 等同于 flex: 1 1 0% */
}

.flex-item-auto {
  flex: auto; /* 等同于 flex: 1 1 auto */
}

.flex-item-none {
  flex: none; /* 等同于 flex: 0 0 auto */
}

.flex-item-custom {
  flex: 2 2 200px; /* flex-grow: 2; flex-shrink: 2; flex-basis: 200px; */
}

align-self

允许单个项目有与其他项目不一样的对齐方式,可覆盖 align-items 属性:

css
.flex-item {
  align-self: auto; /* 默认值,继承父元素的 align-items */
}

.flex-item-flex-start {
  align-self: flex-start;
}

.flex-item-flex-end {
  align-self: flex-end;
}

.flex-item-center {
  align-self: center;
}

.flex-item-baseline {
  align-self: baseline;
}

.flex-item-stretch {
  align-self: stretch;
}

基本示例

简单的 Flex 布局

html
<!DOCTYPE html>
<html>
<head>
  <style>
    .flex-container {
      display: flex;
      background-color: #f0f0f0;
      padding: 10px;
      border-radius: 5px;
    }
    
    .flex-item {
      background-color: #3498db;
      color: white;
      padding: 20px;
      margin: 10px;
      border-radius: 5px;
      text-align: center;
    }
  </style>
</head>
<body>
  <div class="flex-container">
    <div class="flex-item">项目1</div>
    <div class="flex-item">项目2</div>
    <div class="flex-item">项目3</div>
  </div>
</body>
</html>

水平垂直居中

html
<!DOCTYPE html>
<html>
<head>
  <style>
    .center-container {
      display: flex;
      justify-content: center;
      align-items: center;
      height: 300px;
      background-color: #f0f0f0;
      border-radius: 5px;
    }
    
    .centered-item {
      background-color: #3498db;
      color: white;
      padding: 30px;
      border-radius: 5px;
    }
  </style>
</head>
<body>
  <div class="center-container">
    <div class="centered-item">居中的内容</div>
  </div>
</body>
</html>

创建导航栏

html
<!DOCTYPE html>
<html>
<head>
  <style>
    .navbar {
      display: flex;
      justify-content: space-between;
      align-items: center;
      background-color: #333;
      padding: 0 20px;
      height: 60px;
    }
    
    .logo {
      color: white;
      font-size: 1.5em;
      font-weight: bold;
    }
    
    .nav-links {
      display: flex;
      list-style: none;
    }
    
    .nav-links li {
      margin: 0 15px;
    }
    
    .nav-links a {
      color: white;
      text-decoration: none;
      padding: 10px 15px;
      border-radius: 4px;
      transition: background-color 0.3s;
    }
    
    .nav-links a:hover {
      background-color: #555;
    }
    
    .nav-button {
      background-color: #3498db;
      color: white;
      border: none;
      padding: 10px 20px;
      border-radius: 4px;
      cursor: pointer;
    }
  </style>
</head>
<body>
  <nav class="navbar">
    <div class="logo">我的网站</div>
    <ul class="nav-links">
      <li><a href="#home">首页</a></li>
      <li><a href="#about">关于</a></li>
      <li><a href="#services">服务</a></li>
      <li><a href="#contact">联系</a></li>
    </ul>
    <button class="nav-button">登录</button>
  </nav>
</body>
</html>

实际应用示例

卡片布局

html
<!DOCTYPE html>
<html>
<head>
  <style>
    .card-container {
      display: flex;
      flex-wrap: wrap;
      gap: 20px;
      padding: 20px;
    }
    
    .card {
      flex: 1 1 300px; /* 允许伸缩,基础宽度300px */
      background-color: white;
      border-radius: 8px;
      box-shadow: 0 2px 10px rgba(0,0,0,0.1);
      overflow: hidden;
    }
    
    .card-image {
      width: 100%;
      height: 200px;
      background-color: #3498db;
      display: flex;
      align-items: center;
      justify-content: center;
      color: white;
      font-size: 1.5em;
    }
    
    .card-content {
      padding: 20px;
    }
    
    .card-title {
      margin-top: 0;
      color: #333;
    }
    
    .card-text {
      color: #666;
      line-height: 1.6;
    }
  </style>
</head>
<body>
  <div class="card-container">
    <div class="card">
      <div class="card-image">图片</div>
      <div class="card-content">
        <h3 class="card-title">卡片标题1</h3>
        <p class="card-text">这是卡片的内容描述,可以包含文本、图像等元素。Flexbox 使卡片布局变得非常简单和灵活。</p>
      </div>
    </div>
    
    <div class="card">
      <div class="card-image">图片</div>
      <div class="card-content">
        <h3 class="card-title">卡片标题2</h3>
        <p class="card-text">通过设置 flex 属性,我们可以轻松控制卡片的大小和排列方式,适应不同的屏幕尺寸。</p>
      </div>
    </div>
    
    <div class="card">
      <div class="card-image">图片</div>
      <div class="card-content">
        <h3 class="card-title">卡片标题3</h3>
        <p class="card-text">使用 gap 属性可以轻松设置卡片之间的间距,而不需要使用 margin。</p>
      </div>
    </div>
  </div>
</body>
</html>

媒体对象布局

html
<!DOCTYPE html>
<html>
<head>
  <style>
    .media {
      display: flex;
      align-items: flex-start;
      padding: 20px;
      border: 1px solid #ddd;
      border-radius: 5px;
      margin-bottom: 20px;
    }
    
    .media-figure {
      margin-right: 20px;
    }
    
    .media-figure img {
      width: 100px;
      height: 100px;
      background-color: #3498db;
      border-radius: 5px;
    }
    
    .media-body {
      flex: 1;
    }
    
    .media-title {
      margin-top: 0;
      margin-bottom: 10px;
      color: #333;
    }
    
    .media-text {
      margin: 0 0 10px 0;
      color: #666;
      line-height: 1.6;
    }
    
    .media-actions {
      display: flex;
      gap: 10px;
    }
    
    .media-button {
      padding: 5px 10px;
      background-color: #f0f0f0;
      border: none;
      border-radius: 3px;
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="media">
    <div class="media-figure">
      <img src="#" alt="头像">
    </div>
    <div class="media-body">
      <h4 class="media-title">用户名称</h4>
      <p class="media-text">这是用户发布的评论内容。Flexbox 的 align-items: flex-start 属性确保头像和文本顶部对齐,创建经典的媒体对象布局。</p>
      <div class="media-actions">
        <button class="media-button">点赞</button>
        <button class="media-button">回复</button>
      </div>
    </div>
  </div>
  
  <div class="media">
    <div class="media-figure">
      <img src="#" alt="头像">
    </div>
    <div class="media-body">
      <h4 class="media-title">另一个用户</h4>
      <p class="media-text">Flexbox 使得创建这种响应式布局变得非常简单。在小屏幕上,内容会自动调整以适应可用空间。</p>
      <div class="media-actions">
        <button class="media-button">点赞</button>
        <button class="media-button">回复</button>
      </div>
    </div>
  </div>
</body>
</html>

响应式 Flexbox

响应式导航栏

html
<!DOCTYPE html>
<html>
<head>
  <style>
    .responsive-nav {
      display: flex;
      flex-wrap: wrap;
      justify-content: space-between;
      align-items: center;
      background-color: #333;
      padding: 10px 20px;
    }
    
    .nav-logo {
      color: white;
      font-size: 1.5em;
      font-weight: bold;
    }
    
    .nav-menu {
      display: flex;
      list-style: none;
      margin: 0;
      padding: 0;
    }
    
    .nav-menu li {
      margin: 0 10px;
    }
    
    .nav-menu a {
      color: white;
      text-decoration: none;
      padding: 10px;
      border-radius: 4px;
    }
    
    .nav-menu a:hover {
      background-color: #555;
    }
    
    .nav-toggle {
      display: none;
      background: none;
      border: none;
      color: white;
      font-size: 1.5em;
      cursor: pointer;
    }
    
    @media (max-width: 768px) {
      .nav-menu {
        flex-direction: column;
        width: 100%;
        display: none;
      }
      
      .nav-menu.active {
        display: flex;
      }
      
      .nav-toggle {
        display: block;
      }
      
      .nav-menu li {
        margin: 5px 0;
        width: 100%;
        text-align: center;
      }
    }
  </style>
</head>
<body>
  <nav class="responsive-nav">
    <div class="nav-logo">我的网站</div>
    <button class="nav-toggle">☰</button>
    <ul class="nav-menu" id="navMenu">
      <li><a href="#home">首页</a></li>
      <li><a href="#about">关于</a></li>
      <li><a href="#services">服务</a></li>
      <li><a href="#portfolio">作品</a></li>
      <li><a href="#contact">联系</a></li>
    </ul>
  </nav>
  
  <script>
    document.querySelector('.nav-toggle').addEventListener('click', function() {
      document.getElementById('navMenu').classList.toggle('active');
    });
  </script>
</body>
</html>

Flexbox 与 Grid 的比较

Flexbox 适用场景

html
<!DOCTYPE html>
<html>
<head>
  <style>
    .comparison {
      font-family: Arial, sans-serif;
      margin: 20px;
    }
    
    .section-title {
      text-align: center;
      margin: 30px 0;
      color: #333;
    }
    
    /* Flexbox 示例 - 一维布局 */
    .flex-example {
      display: flex;
      gap: 20px;
      padding: 20px;
      background-color: #f8f9fa;
      border-radius: 5px;
    }
    
    .flex-item {
      flex: 1;
      padding: 20px;
      background-color: #3498db;
      color: white;
      text-align: center;
      border-radius: 5px;
    }
    
    /* Grid 示例 - 二维布局 */
    .grid-example {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 20px;
      padding: 20px;
      background-color: #f8f9fa;
      border-radius: 5px;
    }
    
    .grid-item {
      padding: 20px;
      background-color: #e74c3c;
      color: white;
      text-align: center;
      border-radius: 5px;
    }
  </style>
</head>
<body>
  <div class="comparison">
    <h2 class="section-title">Flexbox 一维布局</h2>
    <div class="flex-example">
      <div class="flex-item">项目1</div>
      <div class="flex-item">项目2</div>
      <div class="flex-item">项目3</div>
    </div>
    
    <h2 class="section-title">Grid 二维布局</h2>
    <div class="grid-example">
      <div class="grid-item">项目1</div>
      <div class="grid-item">项目2</div>
      <div class="grid-item">项目3</div>
      <div class="grid-item">项目4</div>
      <div class="grid-item">项目5</div>
      <div class="grid-item">项目6</div>
    </div>
  </div>
</body>
</html>

最佳实践

  1. 选择合适的布局方式:一维布局用 Flexbox,二维布局用 Grid
  2. 合理使用 flex 属性:理解 flex-grow、flex-shrink 和 flex-basis 的作用
  3. 注意浏览器兼容性:现代浏览器都支持 Flexbox
  4. 避免过度嵌套:复杂的布局可能需要结合多种技术
  5. 考虑响应式设计:使用媒体查询调整 Flexbox 行为

浏览器兼容性

Flexbox 在现代浏览器中有很好的支持:

  • Chrome 29+
  • Firefox 28+
  • Safari 9+
  • Edge
  • Internet Explorer 11+(部分支持)

总结

Flexbox 是现代 CSS 布局的重要工具,特别适合创建一维布局。它的主要优势包括:

  • 简化了居中对齐的实现
  • 提供了灵活的空间分配机制
  • 支持响应式设计
  • 减少了对浮动和定位的依赖

掌握 Flexbox 对于现代 Web 开发至关重要。在下一章节中,我们将学习更强大的 Grid 布局 技术。