Skip to content

Flexbox 实际应用:解决真实世界的布局难题

学习理论知识很重要,但真正的挑战在于将知识应用到实际项目中。就像学习驾驶,你可以背下所有交通规则,但只有真正上路,面对各种实际情况,才能成为一名合格的司机。

在前面的章节中,我们学习了 Flexbox 的各种属性。现在,让我们通过一系列实际案例来看看如何使用 Flexbox 解决真实世界中的布局问题。这些案例都是从实际项目中提炼出来的,每一个都经过了实战检验。

导航栏模式

导航栏是几乎每个网站都要面对的布局问题。Flexbox 让创建各种类型的导航栏变得异常简单。

基础水平导航栏

最基本的导航栏:Logo 在左边,链接在右边。

html
<nav class="navbar">
  <div class="logo">TechCorp</div>
  <ul class="nav-links">
    <li><a href="#home">Home</a></li>
    <li><a href="#products">Products</a></li>
    <li><a href="#about">About</a></li>
    <li><a href="#contact">Contact</a></li>
  </ul>
</nav>
css
.navbar {
  display: flex;
  justify-content: space-between; /* Logo 和链接分居两端 */
  align-items: center; /* 垂直居中 */
  padding: 15px 40px;
  background-color: #2c3e50;
}

.logo {
  color: white;
  font-size: 24px;
  font-weight: bold;
}

.nav-links {
  display: flex;
  gap: 30px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.nav-links a {
  color: white;
  text-decoration: none;
  padding: 8px 15px;
  border-radius: 4px;
  transition: background-color 0.3s;
}

.nav-links a:hover {
  background-color: #34495e;
}

这个简单的导航栏只用了两个关键属性:justify-content: space-betweenalign-items: center。Logo 和链接自动分居两端,所有元素垂直居中。无论导航栏多宽,布局都会自动适应。

三段式导航栏

很多网站需要更复杂的导航栏:左边是 Logo,中间是主导航,右边是用户操作按钮。

html
<nav class="navbar-advanced">
  <div class="nav-section nav-left">
    <div class="logo">TechCorp</div>
  </div>

  <div class="nav-section nav-center">
    <ul class="nav-links">
      <li><a href="#" class="active">Home</a></li>
      <li><a href="#">Products</a></li>
      <li><a href="#">Services</a></li>
      <li><a href="#">About</a></li>
    </ul>
  </div>

  <div class="nav-section nav-right">
    <button class="btn-secondary">Login</button>
    <button class="btn-primary">Sign Up</button>
  </div>
</nav>
css
.navbar-advanced {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 15px 40px;
  background-color: white;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.nav-section {
  display: flex;
  align-items: center;
}

.nav-left,
.nav-right {
  flex: 0 1 auto; /* 不扩展,可以收缩 */
}

.nav-center {
  flex: 1 1 auto; /* 占据中间所有剩余空间 */
  justify-content: center; /* 导航链接居中 */
}

.logo {
  font-size: 24px;
  font-weight: bold;
  color: #2196f3;
}

.nav-links {
  display: flex;
  gap: 25px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.nav-links a {
  color: #333;
  text-decoration: none;
  padding: 8px 15px;
  border-radius: 4px;
  font-weight: 500;
  transition: all 0.3s;
}

.nav-links a.active,
.nav-links a:hover {
  background-color: #e3f2fd;
  color: #2196f3;
}

.nav-right {
  gap: 15px;
}

.btn-secondary,
.btn-primary {
  padding: 10px 24px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-weight: 500;
  transition: all 0.3s;
}

.btn-secondary {
  background-color: transparent;
  color: #2196f3;
  border: 1px solid #2196f3;
}

.btn-secondary:hover {
  background-color: #e3f2fd;
}

.btn-primary {
  background-color: #2196f3;
  color: white;
}

.btn-primary:hover {
  background-color: #1976d2;
}

关键点在于中间部分使用 flex: 1 占据所有剩余空间,并通过 justify-content: center 让导航链接在这个空间中居中。

垂直侧边栏导航

对于管理后台或应用界面,通常需要垂直的侧边栏导航。

html
<aside class="sidebar-nav">
  <div class="sidebar-header">
    <div class="logo">Dashboard</div>
    <div class="user-info">
      <img src="avatar.jpg" alt="User" class="avatar" />
      <div class="user-details">
        <div class="user-name">Sarah Johnson</div>
        <div class="user-role">Administrator</div>
      </div>
    </div>
  </div>

  <nav class="nav-menu">
    <a href="#" class="nav-item active">
      <span class="icon">🏠</span>
      <span class="label">Dashboard</span>
    </a>
    <a href="#" class="nav-item">
      <span class="icon">📊</span>
      <span class="label">Analytics</span>
    </a>
    <a href="#" class="nav-item">
      <span class="icon">👥</span>
      <span class="label">Users</span>
    </a>
    <a href="#" class="nav-item">
      <span class="icon">⚙️</span>
      <span class="label">Settings</span>
    </a>
  </nav>

  <div class="sidebar-footer">
    <button class="btn-logout">Logout</button>
  </div>
</aside>
css
.sidebar-nav {
  display: flex;
  flex-direction: column; /* 垂直排列 */
  width: 280px;
  height: 100vh;
  background-color: #2c3e50;
  color: white;
}

.sidebar-header {
  padding: 25px 20px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.logo {
  font-size: 22px;
  font-weight: bold;
  margin-bottom: 20px;
}

.user-info {
  display: flex;
  align-items: center;
  gap: 12px;
}

.avatar {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: 2px solid #3498db;
}

.user-details {
  flex: 1;
}

.user-name {
  font-weight: 600;
  margin-bottom: 4px;
}

.user-role {
  font-size: 12px;
  color: #95a5a6;
}

.nav-menu {
  flex: 1; /* 占据所有剩余空间 */
  display: flex;
  flex-direction: column;
  padding: 20px 0;
  overflow-y: auto; /* 如果导航项太多,允许滚动 */
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 15px;
  padding: 15px 25px;
  color: white;
  text-decoration: none;
  transition: background-color 0.3s;
  cursor: pointer;
}

.nav-item:hover {
  background-color: #34495e;
}

.nav-item.active {
  background-color: #3498db;
  border-left: 4px solid #2980b9;
}

.icon {
  font-size: 20px;
  width: 24px;
  text-align: center;
}

.label {
  font-weight: 500;
}

.sidebar-footer {
  padding: 20px;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
}

.btn-logout {
  width: 100%;
  padding: 12px;
  background-color: #e74c3c;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-weight: 500;
  transition: background-color 0.3s;
}

.btn-logout:hover {
  background-color: #c0392b;
}

这个垂直导航的关键是使用 flex-direction: column 和让导航菜单部分 flex: 1 占据所有剩余空间,这样无论窗口多高,底部的按钮都会保持在底部。

卡片布局模式

卡片布局是现代网页设计中最常见的模式之一。Flexbox 让创建灵活的卡片网格变得简单。

等宽卡片网格

最基本的卡片网格,所有卡片等宽等高。

html
<div class="card-grid">
  <div class="card">
    <img src="product1.jpg" alt="Product" class="card-image" />
    <div class="card-content">
      <h3>Wireless Headphones</h3>
      <p>Premium sound quality with active noise cancellation</p>
      <div class="card-footer">
        <span class="price">$299</span>
        <button class="btn-add">Add to Cart</button>
      </div>
    </div>
  </div>

  <div class="card">
    <img src="product2.jpg" alt="Product" class="card-image" />
    <div class="card-content">
      <h3>Smart Watch</h3>
      <p>Track your health and stay connected on the go</p>
      <div class="card-footer">
        <span class="price">$399</span>
        <button class="btn-add">Add to Cart</button>
      </div>
    </div>
  </div>

  <div class="card">
    <img src="product3.jpg" alt="Product" class="card-image" />
    <div class="card-content">
      <h3>Laptop Stand</h3>
      <p>Ergonomic design for better posture and comfort during work</p>
      <div class="card-footer">
        <span class="price">$79</span>
        <button class="btn-add">Add to Cart</button>
      </div>
    </div>
  </div>
</div>
css
.card-grid {
  display: flex;
  flex-wrap: wrap; /* 允许换行 */
  gap: 25px;
  padding: 30px;
}

.card {
  flex: 1 1 calc(33.333% - 25px); /* 每行 3 张卡片 */
  min-width: 280px; /* 最小宽度,确保在小屏幕上可读 */
  display: flex;
  flex-direction: column; /* 卡片内容垂直排列 */
  background-color: white;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  transition: transform 0.3s, box-shadow 0.3s;
}

.card:hover {
  transform: translateY(-8px);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
}

.card-image {
  width: 100%;
  height: 220px;
  object-fit: cover;
}

.card-content {
  flex: 1; /* 占据剩余空间 */
  display: flex;
  flex-direction: column;
  padding: 25px;
}

.card-content h3 {
  margin: 0 0 12px 0;
  font-size: 20px;
  color: #333;
}

.card-content p {
  flex: 1; /* 描述文字占据剩余空间 */
  margin: 0 0 20px 0;
  color: #666;
  line-height: 1.6;
}

.card-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: auto; /* 确保footer在底部 */
}

.price {
  font-size: 24px;
  font-weight: bold;
  color: #2196f3;
}

.btn-add {
  padding: 10px 20px;
  background-color: #2196f3;
  color: white;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-weight: 500;
  transition: background-color 0.3s;
}

.btn-add:hover {
  background-color: #1976d2;
}

这个布局的关键点:

  1. 使用 flex-wrap: wrap 允许卡片换行
  2. 每张卡片 flex: 1 1 calc(33.333% - 25px) 确保每行显示 3 张
  3. 设置 min-width: 280px 确保在小屏幕上卡片不会太窄
  4. 卡片内部也使用 Flexbox,让描述文字 flex: 1 占据空间,按钮始终在底部

不同尺寸的卡片

有时候我们需要突出某些卡片,让它们占据更多空间。

css
.card-featured {
  flex: 2 1 calc(66.666% - 25px); /* 占据 2/3 宽度 */
}

.card-small {
  flex: 1 1 calc(25% - 25px); /* 每行 4 张小卡片 */
}
html
<div class="card-grid">
  <div class="card card-featured">
    <!-- 特色卡片,占据更大空间 -->
  </div>
  <div class="card"><!-- 普通卡片 --></div>
  <div class="card"><!-- 普通卡片 --></div>
  <div class="card card-small"><!-- 小卡片 --></div>
  <div class="card card-small"><!-- 小卡片 --></div>
</div>

表单布局

Flexbox 非常适合创建各种表单布局,从简单的登录表单到复杂的多列表单。

内联表单

搜索栏、newsletter 订阅等简短表单通常是水平排列的。

html
<form class="inline-form">
  <input type="email" placeholder="Enter your email" class="form-input" />
  <button type="submit" class="form-submit">Subscribe</button>
</form>
css
.inline-form {
  display: flex;
  gap: 0; /* 无间隙,让输入框和按钮紧密相连 */
  max-width: 500px;
  margin: 30px auto;
}

.form-input {
  flex: 1; /* 输入框占据所有剩余空间 */
  padding: 14px 20px;
  border: 2px solid #e0e0e0;
  border-right: none; /* 移除右边框 */
  border-radius: 4px 0 0 4px; /* 左侧圆角 */
  font-size: 16px;
  outline: none;
  transition: border-color 0.3s;
}

.form-input:focus {
  border-color: #2196f3;
}

.form-submit {
  flex: 0 0 auto; /* 不扩展不收缩 */
  padding: 14px 32px;
  background-color: #2196f3;
  color: white;
  border: 2px solid #2196f3;
  border-radius: 0 4px 4px 0; /* 右侧圆角 */
  cursor: pointer;
  font-size: 16px;
  font-weight: 600;
  transition: background-color 0.3s;
}

.form-submit:hover {
  background-color: #1976d2;
  border-color: #1976d2;
}

表单字段组

复杂表单通常需要组织成多列布局。

html
<form class="user-form">
  <div class="form-row">
    <div class="form-group">
      <label for="firstName">First Name</label>
      <input type="text" id="firstName" required />
    </div>
    <div class="form-group">
      <label for="lastName">Last Name</label>
      <input type="text" id="lastName" required />
    </div>
  </div>

  <div class="form-row">
    <div class="form-group">
      <label for="email">Email Address</label>
      <input type="email" id="email" required />
    </div>
  </div>

  <div class="form-row">
    <div class="form-group">
      <label for="city">City</label>
      <input type="text" id="city" />
    </div>
    <div class="form-group">
      <label for="state">State</label>
      <input type="text" id="state" />
    </div>
    <div class="form-group">
      <label for="zip">ZIP Code</label>
      <input type="text" id="zip" />
    </div>
  </div>

  <div class="form-actions">
    <button type="button" class="btn-cancel">Cancel</button>
    <button type="submit" class="btn-submit">Submit</button>
  </div>
</form>
css
.user-form {
  max-width: 800px;
  margin: 40px auto;
  padding: 40px;
  background-color: white;
  border-radius: 12px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
}

.form-row {
  display: flex;
  gap: 20px;
  margin-bottom: 25px;
}

.form-group {
  flex: 1; /* 所有字段平均分配空间 */
  display: flex;
  flex-direction: column;
}

.form-group label {
  margin-bottom: 8px;
  font-weight: 600;
  color: #333;
  font-size: 14px;
}

.form-group input {
  padding: 12px 16px;
  border: 2px solid #e0e0e0;
  border-radius: 6px;
  font-size: 15px;
  transition: border-color 0.3s;
}

.form-group input:focus {
  outline: none;
  border-color: #2196f3;
}

.form-actions {
  display: flex;
  justify-content: flex-end; /* 按钮靠右 */
  gap: 15px;
  margin-top: 35px;
  padding-top: 25px;
  border-top: 1px solid #e0e0e0;
}

.btn-cancel,
.btn-submit {
  padding: 12px 32px;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-size: 16px;
  font-weight: 600;
  transition: all 0.3s;
}

.btn-cancel {
  background-color: transparent;
  color: #666;
  border: 2px solid #e0e0e0;
}

.btn-cancel:hover {
  background-color: #f5f5f5;
}

.btn-submit {
  background-color: #2196f3;
  color: white;
}

.btn-submit:hover {
  background-color: #1976d2;
}

圣杯布局(Holy Grail Layout)

圣杯布局是一个经典的三列布局问题:固定宽度的左右侧边栏,弹性的中间内容区,header 和 footer。在 Flexbox 之前,这个布局需要复杂的技巧。

html
<div class="holy-grail">
  <header class="header">
    <h1>Website Header</h1>
  </header>

  <div class="content-wrapper">
    <nav class="left-sidebar">
      <h3>Navigation</h3>
      <ul>
        <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>
    </nav>

    <main class="main-content">
      <h2>Main Content</h2>
      <p>
        This is the main content area that will expand to fill all available
        space.
      </p>
      <p>It can contain articles, posts, or any primary content.</p>
    </main>

    <aside class="right-sidebar">
      <h3>Sidebar</h3>
      <div class="widget">
        <h4>Recent Posts</h4>
        <ul>
          <li>Post 1</li>
          <li>Post 2</li>
          <li>Post 3</li>
        </ul>
      </div>
    </aside>
  </div>

  <footer class="footer">
    <p>&copy; 2025 TechCorp. All rights reserved.</p>
  </footer>
</div>
css
.holy-grail {
  display: flex;
  flex-direction: column; /* 垂直排列:header、content、footer */
  min-height: 100vh; /* 至少占满整个视口 */
}

.header {
  flex: 0 0 auto; /* 不扩展不收缩 */
  background-color: #2c3e50;
  color: white;
  padding: 30px 40px;
}

.header h1 {
  margin: 0;
}

.content-wrapper {
  display: flex;
  flex: 1; /* 占据所有剩余空间 */
}

.left-sidebar,
.right-sidebar {
  flex: 0 0 250px; /* 固定宽度 250px */
  padding: 30px 25px;
}

.left-sidebar {
  background-color: #ecf0f1;
  order: 1; /* 确保在左侧 */
}

.main-content {
  flex: 1; /* 占据所有剩余空间 */
  padding: 30px 40px;
  background-color: white;
  order: 2; /* 在中间 */
}

.right-sidebar {
  background-color: #f8f9fa;
  order: 3; /* 在右侧 */
}

.footer {
  flex: 0 0 auto;
  background-color: #34495e;
  color: white;
  padding: 25px 40px;
  text-align: center;
}

.footer p {
  margin: 0;
}

/* 响应式:小屏幕时堆叠 */
@media (max-width: 768px) {
  .content-wrapper {
    flex-direction: column;
  }

  .left-sidebar,
  .right-sidebar,
  .main-content {
    flex: 0 0 auto; /* 取消固定宽度 */
    order: initial; /* 重置顺序 */
  }

  /* 调整顺序:内容优先 */
  .main-content {
    order: 1;
  }

  .left-sidebar {
    order: 2;
  }

  .right-sidebar {
    order: 3;
  }
}

这个布局的关键:

  1. 外层容器 flex-direction: column 垂直排列三个主要部分
  2. 中间内容区 flex: 1 占据所有剩余垂直空间
  3. 内层容器水平排列三列,中间列 flex: 1 占据所有剩余水平空间
  4. 在小屏幕上,通过 flex-direction: columnorder 调整布局

完美居中

Flexbox 让各种居中变得异常简单,这是它最受欢迎的特性之一。

单个元素居中

html
<div class="center-container">
  <div class="centered-box">
    <h2>Perfect Center</h2>
    <p>This box is perfectly centered both horizontally and vertically.</p>
  </div>
</div>
css
.center-container {
  display: flex;
  justify-content: center; /* 水平居中 */
  align-items: center; /* 垂直居中 */
  min-height: 500px;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

.centered-box {
  padding: 40px 50px;
  background-color: white;
  border-radius: 12px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
  max-width: 450px;
}

.centered-box h2 {
  margin-top: 0;
  color: #333;
}

就这么简单!两行核心代码实现完美居中。

登录表单居中

一个常见的应用场景是居中的登录表单。

html
<div class="login-page">
  <div class="login-box">
    <h2>Welcome Back</h2>
    <p class="subtitle">Sign in to continue</p>
    <form class="login-form">
      <div class="input-group">
        <input type="email" placeholder="Email address" required />
      </div>
      <div class="input-group">
        <input type="password" placeholder="Password" required />
      </div>
      <div class="form-options">
        <label class="checkbox-label">
          <input type="checkbox" />
          <span>Remember me</span>
        </label>
        <a href="#" class="forgot-password">Forgot password?</a>
      </div>
      <button type="submit" class="btn-login">Sign In</button>
    </form>
    <div class="signup-link">
      Don't have an account? <a href="#">Sign up</a>
    </div>
  </div>
</div>
css
.login-page {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

.login-box {
  width: 100%;
  max-width: 420px;
  padding: 45px 40px;
  background-color: white;
  border-radius: 16px;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
}

.login-box h2 {
  margin: 0 0 8px 0;
  color: #333;
  text-align: center;
  font-size: 28px;
}

.subtitle {
  margin: 0 0 35px 0;
  color: #666;
  text-align: center;
}

.login-form {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.input-group input {
  width: 100%;
  padding: 14px 18px;
  border: 2px solid #e0e0e0;
  border-radius: 8px;
  font-size: 15px;
  transition: border-color 0.3s;
}

.input-group input:focus {
  outline: none;
  border-color: #667eea;
}

.form-options {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 14px;
}

.checkbox-label {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
}

.forgot-password {
  color: #667eea;
  text-decoration: none;
}

.forgot-password:hover {
  text-decoration: underline;
}

.btn-login {
  width: 100%;
  padding: 14px;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  border: none;
  border-radius: 8px;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  transition: transform 0.3s;
}

.btn-login:hover {
  transform: translateY(-2px);
}

.signup-link {
  margin-top: 25px;
  text-align: center;
  color: #666;
  font-size: 14px;
}

.signup-link a {
  color: #667eea;
  text-decoration: none;
  font-weight: 600;
}

.signup-link a:hover {
  text-decoration: underline;
}

让 footer 始终保持在页面底部是另一个经典问题。当内容很少时,footer 应该在视口底部;当内容很多时,footer 应该在内容下方。

html
<div class="page">
  <header class="page-header">
    <h1>My Website</h1>
    <nav>
      <a href="#">Home</a>
      <a href="#">About</a>
      <a href="#">Contact</a>
    </nav>
  </header>

  <main class="page-content">
    <h2>Welcome</h2>
    <p>This is the main content area.</p>
    <p>
      Even if there's not much content, the footer will stay at the bottom of
      the viewport.
    </p>
  </main>

  <footer class="page-footer">
    <p>&copy; 2025 TechCorp. All rights reserved.</p>
  </footer>
</div>
css
.page {
  display: flex;
  flex-direction: column;
  min-height: 100vh; /* 关键:最小高度为视口高度 */
}

.page-header {
  flex: 0 0 auto; /* 不扩展不收缩 */
  padding: 25px 40px;
  background-color: #2c3e50;
  color: white;
}

.page-header h1 {
  margin: 0 0 15px 0;
}

.page-header nav {
  display: flex;
  gap: 25px;
}

.page-header nav a {
  color: white;
  text-decoration: none;
}

.page-content {
  flex: 1; /* 占据所有剩余空间 */
  padding: 40px;
  max-width: 1200px;
  width: 100%;
  margin: 0 auto;
}

.page-footer {
  flex: 0 0 auto; /* 不扩展不收缩 */
  padding: 25px 40px;
  background-color: #34495e;
  color: white;
  text-align: center;
}

.page-footer p {
  margin: 0;
}

关键点:

  1. 容器 min-height: 100vh 确保至少占满视口
  2. Header 和 footer flex: 0 0 auto 保持自然高度
  3. Main content flex: 1 占据所有剩余空间,把 footer 推到底部

常见问题与解决方案

问题 1:Flex 项目溢出容器

问题描述:当 flex 项目有很长的文本或图片时,可能会溢出容器。

css
/* 问题代码 */
.item {
  flex: 1;
  /* 长文本会撑开容器 */
}

解决方案:添加 min-width: 0overflow: hidden

css
.item {
  flex: 1;
  min-width: 0; /* 允许项目缩小到内容宽度以下 */
  overflow: hidden; /* 或者隐藏溢出内容 */
}

.item img {
  max-width: 100%; /* 图片不超过容器宽度 */
  height: auto;
}

问题 2:垂直居中不生效

问题描述:设置了 align-items: center 但垂直居中不生效。

原因:容器没有明确的高度。

解决方案:给容器设置高度

css
.container {
  display: flex;
  align-items: center;
  min-height: 400px; /* 或height: 100vh */
}

问题 3:Gap 在旧浏览器不支持

问题描述gap 属性在一些旧浏览器中不支持。

解决方案:使用 margin 作为降级方案

css
.container {
  display: flex;
  margin: -10px; /* 负margin抵消子元素的margin */
}

.item {
  margin: 10px; /* 所有项目都有margin */
}

/* 或者使用特性检测 */
@supports (gap: 20px) {
  .container {
    gap: 20px;
    margin: 0;
  }

  .item {
    margin: 0;
  }
}

最佳实践总结

基于实际项目经验,以下是使用 Flexbox 的最佳实践:

1. 始终从简单开始

css
/* 从基础开始 */
.container {
  display: flex;
}

/* 根据需要逐步添加 */
.container {
  display: flex;
  gap: 20px;
  align-items: center;
}

2. 使用语义化的类名

css
/* 好的做法 */
.navbar,
.card-grid,
.form-actions {
  display: flex;
}

/* 避免 */
.flex-container,
.flex-wrapper {
  display: flex;
}

3. 移动优先的响应式设计

css
/* 移动端先 */
.container {
  flex-direction: column;
}

/* 然后桌面端 */
@media (min-width: 768px) {
  .container {
    flex-direction: row;
  }
}

4. 优先使用 flex 简写

css
/* 推荐:简洁明确 */
.item {
  flex: 1;
}

/* 避免:除非需要精确控制 */
.item {
  flex-grow: 1;
  flex-shrink: 1;
  flex-basis: 0%;
}

5. 考虑可访问性

css
/* 谨慎使用 order,它会影响键盘导航 */
.item {
  order: 2; /* 确保逻辑顺序仍然合理 */
}

6. 使用 gap 而不是 margin(如果可以)

css
/* 现代做法 */
.container {
  display: flex;
  gap: 20px;
}

/* 传统做法:更复杂 */
.container {
  display: flex;
  margin: -10px;
}

.item {
  margin: 10px;
}

总结

Flexbox 在实际项目中的应用非常广泛。我们通过这些案例学到了:

核心模式:

  • 导航栏:使用 justify-content: space-betweenalign-items: center
  • 卡片布局:使用 flex-wrap: wrapflex: 1 1 calc(...)
  • 表单:结合 flex: 1 和垂直 flex-direction: column
  • 圣杯布局:嵌套 Flexbox 容器处理复杂布局
  • 居中justify-content: center + align-items: center
  • Sticky Footermin-height: 100vh + flex: 1 在主内容区

关键技巧:

  1. 合理使用 flex 简写控制项目尺寸
  2. 使用 gap 简化间距控制
  3. 嵌套 Flexbox 容器处理复杂布局
  4. 使用 order 在响应式设计中重排元素
  5. 结合媒体查询实现响应式布局

掌握这些实际应用模式后,你就能用 Flexbox 解决大部分布局问题。在下一节中,我们将学习如何用 Flexbox 创建真正的响应式设计。