📑 文章目录

在前端开发中,布局是页面呈现的骨架。从早期的 table 布局、float 布局,到如今的 Flexbox 和 CSS Grid,布局方式经历了翻天覆地的变化。本文将系统性地梳理 Flexbox 和 Grid 的核心概念,并通过实战案例展示如何用它们构建复杂且优雅的响应式页面。

一、Flexbox:一维布局之王

Flexbox(弹性盒子布局)是一个一维布局模型,擅长处理行或列方向上的元素排列。它最大的优势在于灵活处理元素的对齐、分布和自适应空间。

1.1 基本概念

Flex 布局由容器(flex container)和项目(flex item)组成。容器通过 display: flex 声明,内部子元素自动成为弹性项目。

.container {
  display: flex;
  justify-content: center;  /* 主轴对齐 */
  align-items: center;       /* 交叉轴对齐 */
  gap: 16px;                 /* 项目间距 */
}

.item {
  flex: 1;                   /* 等分剩余空间 */
  min-width: 0;              /* 防止内容溢出 */
}

1.2 常见布局模式

导航栏布局: Logo 靠左、导航链接居中、操作按钮靠右。这是 Flex 最经典的场景之一。

.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 24px;
  height: 64px;
}

.navbar .logo { flex-shrink: 0; }
.navbar .links { display: flex; gap: 24px; }
.navbar .actions { flex-shrink: 0; }

垂直居中: Flexbox 解决垂直居中只需两行代码,告别了 margin 负值和 transform hack 时代。

.center-box {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

等高列布局: 传统 CSS 实现等高列需要各种 hack,Flexbox 天然支持。

.columns {
  display: flex;
  gap: 20px;
}

.columns > div {
  flex: 1;          /* 所有列自动等高 */
  padding: 20px;
  background: #fff;
}

1.3 Flex 实用技巧

flex: 1flex-grow: 1; flex-shrink: 1; flex-basis: 0% 的简写。理解这三个属性才能精确控制元素行为:

  • flex-grow:空间有剩余时,项目如何放大(默认 0,不放大)
  • flex-shrink:空间不足时,项目如何缩小(默认 1,可缩小)
  • flex-basis:项目在分配空间前的初始尺寸(默认 auto)
/* 经典的"固定侧边栏 + 自适应内容"布局 */
.sidebar { flex: 0 0 280px; }  /* 不放大不缩小,固定 280px */
.main    { flex: 1; }          /* 占满剩余空间 */

换行与间距: 当项目过多需要换行时,使用 flex-wrap: wrap 配合 gap 属性控制间距。

.card-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
}

.card-grid > .card {
  flex: 1 1 300px;  /* 最小宽度 300px,空间够则等分 */
  max-width: calc(50% - 10px); /* 限制最大宽度 */
}

二、CSS Grid:二维布局的终极方案

如果说 Flexbox 擅长一维(行或列),那么 CSS Grid 就是二维布局的王者——它可以同时控制行和列。

2.1 基本概念

.grid-container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);  /* 三列等宽 */
  grid-template-rows: auto;                /* 行高自适应内容 */
  gap: 24px;
  padding: 24px;
}

fr 单位是 Grid 独有的弹性单位,1fr 表示一份可用空间。配合 repeat() 函数可以快速创建网格。

2.2 经典布局案例

圣杯布局: 头部 + 左侧导航 + 主内容区 + 右侧边栏 + 底部。这是 Grid 最擅长的场景:

.holy-grail {
  display: grid;
  grid-template-columns: 240px 1fr 300px;
  grid-template-rows: 64px 1fr 48px;
  grid-template-areas:
    "header  header  header"
    "sidebar main    aside"
    "footer  footer  footer";
  min-height: 100vh;
}

.header  { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main    { grid-area: main; }
.aside   { grid-area: aside; }
.footer  { grid-area: footer; }

/* 响应式:小屏变单列 */
@media (max-width: 768px) {
  .holy-grail {
    grid-template-columns: 1fr;
    grid-template-areas:
      "header"
      "main"
      "sidebar"
      "aside"
      "footer";
  }
}

自适应网格: 使用 auto-fit / auto-fill + minmax() 实现无需媒体查询的响应式布局:

.responsive-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 24px;
}

这段代码的魔法在于:每列最小 280px,空间够则放更多列,空间不够自动换行。一个属性搞定响应式,不需要写任何 @media 查询。

2.3 Grid 高级技巧

跨行跨列: 让某个元素跨越多行或多列:

.featured {
  grid-column: span 2;    /* 横跨两列 */
  grid-row: span 2;       /* 纵跨两行 */
}

/* 或者精确指定位置 */
.hero-card {
  grid-column: 1 / -1;    /* 从第1条线到最后一条线,占满整行 */
}

子网格(Subgrid): CSS Subgrid 允许子元素继承父网格的轨道定义,实现嵌套布局的对齐:

.card {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: span 3;    /* 继承父网格的 3 列轨道 */
}

.card .title  { grid-column: 1; }
.card .body   { grid-column: 2; }
.card .action { grid-column: 3; }
/* 子元素与父网格完美对齐 */

隐式网格与自动放置: 未显式定位的项目会按自动放置规则排列。通过 grid-auto-flow: dense 可以让 Grid 自动填充空隙:

.masonry-like {
  display: grid;
  grid-auto-flow: dense;          /* 密集排列,减少空隙 */
  grid-template-columns: repeat(4, 1fr);
}

.tall-item { grid-row: span 2; }  /* 高元素占两行,其他元素自动填充空位 */

三、Flexbox vs Grid:如何选择?

这是一个常见问题。简单来说:

  • Flexbox 适合一维布局:导航栏、工具栏、卡片内部排列、表单
  • Grid 适合二维布局:页面整体布局、卡片网格、仪表盘、图片墙
  • 组合使用:Grid 做大框架,Flexbox 做局部排列——这是最佳实践
/* 实际项目中的典型组合 */
.page-layout {
  display: grid;           /* 二维:整体页面结构 */
  grid-template-columns: 260px 1fr;
  grid-template-rows: 64px 1fr auto;
  grid-template-areas:
    "nav    header"
    "nav    main"
    "nav    footer";
  min-height: 100vh;
}

.page-header {
  display: flex;           /* 一维:头部内部排列 */
  justify-content: space-between;
  align-items: center;
}

.card-list {
  display: grid;           /* 二维:卡片网格 */
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 20px;
}

.card-body {
  display: flex;           /* 一维:卡片内容 */
  flex-direction: column;
  gap: 12px;
}

四、响应式断点策略

响应式布局不仅是技术问题,更是设计决策。以下是经过大量实践验证的断点策略:

/* Mobile First 策略(推荐) */
.container { max-width: 100%; padding: 0 16px; }

/* 平板 ≥ 768px */
@media (min-width: 768px) {
  .container { max-width: 720px; padding: 0 24px; }
  .grid { grid-template-columns: repeat(2, 1fr); }
}

/* 桌面 ≥ 1024px */
@media (min-width: 1024px) {
  .container { max-width: 960px; }
  .grid { grid-template-columns: repeat(3, 1fr); }
}

/* 大屏 ≥ 1280px */
@media (min-width: 1280px) {
  .container { max-width: 1200px; }
  .grid { grid-template-columns: repeat(4, 1fr); }
}

/* 超大屏 ≥ 1536px */
@media (min-width: 1536px) {
  .container { max-width: 1400px; }
}

使用 min-width 而非 max-width 的 Mobile First 策略有几个好处:基础样式面向移动端,CSS 更简洁,性能更好(移动端不需要解析不匹配的 max-width 规则)。

五、实战:构建一个响应式博客首页

综合运用 Grid 和 Flexbox,构建一个完整的博客首页布局:

/* 整体页面结构 - Grid */
.blog-page {
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: auto auto 1fr auto;
  min-height: 100vh;
}

@media (min-width: 1024px) {
  .blog-page {
    grid-template-columns: 1fr 300px;
    grid-template-rows: auto 1fr auto;
    grid-template-areas:
      "header  header"
      "main    sidebar"
      "footer  footer";
  }
}

/* 导航栏 - Flex */
.nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
  height: 64px;
}

/* 文章卡片网格 - Grid */
.article-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;
}

@media (min-width: 768px) {
  .article-grid { grid-template-columns: repeat(2, 1fr); }
}

/* 侧边栏 - Flex 纵向排列 */
.sidebar {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

/* 卡片内部 - Flex */
.article-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.article-card .meta {
  display: flex;
  align-items: center;
  gap: 12px;
}

六、性能与最佳实践

现代 CSS 布局性能已经非常优秀,但仍有一些值得注意的实践:

  • 避免 position: absolute 过度使用: Grid 和 Flexbox 大部分场景可以替代绝对定位
  • gap 代替 margin: gap 属性比 margin 紧凑,不会产生边距折叠问题
  • min-width: 0 防溢出: Flex 项目默认 min-width: auto,内容可能撑破容器
  • auto-fit vs auto-fill auto-fit 会折叠空轨道,auto-fill 保留空轨道
  • content-box vs border-box: 全局设置 box-sizing: border-box 避免尺寸计算问题
/* 推荐的全局重置 */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

/* Flex 防溢出 */
.flex-item {
  flex: 1;
  min-width: 0;  /* 允许项目缩小到内容宽度以下 */
}

Flexbox 和 Grid 的出现彻底改变了 CSS 布局的方式。Flexbox 简化了单一方向的排列,Grid 统治了二维空间。在实际项目中,两者配合使用是最强大的方案——Grid 搭建骨架,Flexbox 调整细节。掌握了它们,你就能轻松应对几乎所有的布局需求。