发布于

CSS Grid 布局完全指南:现代网页布局的终极解决方案

作者

CSS Grid 布局完全指南:现代网页布局的终极解决方案

CSS Grid 是现代 CSS 中最强大的布局系统之一,它为我们提供了二维布局的完整解决方案。本文将深入探讨 Grid 布局的各个方面,帮助你掌握这个强大的工具。

Grid 布局基础概念

什么是 CSS Grid?

CSS Grid 是一个二维布局系统,允许我们同时在行和列两个维度上控制元素的位置和大小。与 Flexbox 的一维布局不同,Grid 提供了更强大的布局能力。

/* 基础 Grid 容器 */
.grid-container {
  display: grid;
  grid-template-columns: 200px 1fr 100px;
  grid-template-rows: auto 1fr auto;
  gap: 20px;
  height: 100vh;
}

.header {
  grid-area: 1 / 1 / 2 / 4;
}
.sidebar {
  grid-area: 2 / 1 / 3 / 2;
}
.main {
  grid-area: 2 / 2 / 3 / 3;
}
.aside {
  grid-area: 2 / 3 / 3 / 4;
}
.footer {
  grid-area: 3 / 1 / 4 / 4;
}

Grid 术语解释

<div class="grid-container">
  <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>
.grid-container {
  display: grid;

  /* 网格轨道(Grid Tracks) */
  grid-template-columns: 1fr 2fr 1fr; /* 列轨道 */
  grid-template-rows: 100px auto; /* 行轨道 */

  /* 网格间隙(Grid Gap) */
  gap: 10px; /* 行间隙和列间隙 */
  /* 或者分别设置 */
  row-gap: 15px;
  column-gap: 20px;

  /* 网格线(Grid Lines)自动生成 */
  /* 列线:1, 2, 3, 4 */
  /* 行线:1, 2, 3 */
}

创建网格容器

1. 显式网格定义

/* 使用具体尺寸 */
.grid-explicit {
  display: grid;
  grid-template-columns: 200px 300px 200px;
  grid-template-rows: 100px 200px;
}

/* 使用 fr 单位(分数单位) */
.grid-fractional {
  display: grid;
  grid-template-columns: 1fr 2fr 1fr; /* 1:2:1 的比例 */
  grid-template-rows: 100px 1fr;
}

/* 使用 repeat() 函数 */
.grid-repeat {
  display: grid;
  grid-template-columns: repeat(3, 1fr); /* 等同于 1fr 1fr 1fr */
  grid-template-rows: repeat(2, 100px);
}

/* 混合使用不同单位 */
.grid-mixed {
  display: grid;
  grid-template-columns: 200px 1fr auto;
  grid-template-rows: auto 1fr 50px;
}

2. 隐式网格

.grid-implicit {
  display: grid;
  grid-template-columns: repeat(3, 1fr);

  /* 当内容超出显式网格时,隐式网格的尺寸 */
  grid-auto-rows: 100px;
  grid-auto-columns: 200px;

  /* 隐式网格项目的放置方向 */
  grid-auto-flow: row; /* 默认值,按行填充 */
  /* grid-auto-flow: column; 按列填充 */
  /* grid-auto-flow: row dense; 紧密填充 */
}

网格项目定位

1. 基于网格线定位

.grid-item-1 {
  /* 使用网格线编号 */
  grid-column-start: 1;
  grid-column-end: 3;
  grid-row-start: 1;
  grid-row-end: 2;

  /* 简写形式 */
  grid-column: 1 / 3;
  grid-row: 1 / 2;

  /* 更简洁的写法 */
  grid-area: 1 / 1 / 2 / 3; /* row-start / col-start / row-end / col-end */
}

.grid-item-2 {
  /* 使用 span 关键字 */
  grid-column: span 2; /* 跨越 2 列 */
  grid-row: span 1; /* 跨越 1 行 */
}

.grid-item-3 {
  /* 使用负数从末尾开始计算 */
  grid-column: 1 / -1; /* 从第一列到最后一列 */
  grid-row: 2 / -1; /* 从第二行到最后一行 */
}

2. 命名网格线

.grid-named-lines {
  display: grid;
  grid-template-columns:
    [sidebar-start] 200px
    [sidebar-end main-start] 1fr
    [main-end aside-start] 200px
    [aside-end];
  grid-template-rows:
    [header-start] 80px
    [header-end content-start] 1fr
    [content-end footer-start] 60px
    [footer-end];
}

.header {
  grid-column: sidebar-start / aside-end;
  grid-row: header-start / header-end;
}

.sidebar {
  grid-column: sidebar-start / sidebar-end;
  grid-row: content-start / content-end;
}

.main {
  grid-column: main-start / main-end;
  grid-row: content-start / content-end;
}

3. 网格区域模板

.grid-template-areas {
  display: grid;
  grid-template-columns: 200px 1fr 200px;
  grid-template-rows: 80px 1fr 60px;
  grid-template-areas:
    'header header header'
    'sidebar main aside'
    'footer footer footer';
  gap: 20px;
}

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

响应式网格布局

1. 自适应列数

/* 自动适应的网格 */
.auto-fit-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 20px;
}

/* auto-fill vs auto-fit */
.auto-fill-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 15px;
}

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

2. 媒体查询结合 Grid

.responsive-grid {
  display: grid;
  gap: 20px;

  /* 移动端:单列布局 */
  grid-template-columns: 1fr;
  grid-template-areas:
    'header'
    'main'
    'sidebar'
    'footer';
}

@media (min-width: 768px) {
  .responsive-grid {
    /* 平板:两列布局 */
    grid-template-columns: 200px 1fr;
    grid-template-areas:
      'header header'
      'sidebar main'
      'footer footer';
  }
}

@media (min-width: 1024px) {
  .responsive-grid {
    /* 桌面:三列布局 */
    grid-template-columns: 200px 1fr 200px;
    grid-template-areas:
      'header header header'
      'sidebar main aside'
      'footer footer footer';
  }
}

高级 Grid 技巧

1. 网格对齐

.grid-alignment {
  display: grid;
  grid-template-columns: repeat(3, 200px);
  grid-template-rows: repeat(3, 100px);
  gap: 10px;
  height: 500px;

  /* 整个网格在容器中的对齐 */
  justify-content: center; /* 水平对齐:start | end | center | stretch | space-around | space-between | space-evenly */
  align-content: center; /* 垂直对齐:start | end | center | stretch | space-around | space-between | space-evenly */

  /* 网格项目在网格区域中的对齐 */
  justify-items: center; /* 水平对齐:start | end | center | stretch */
  align-items: center; /* 垂直对齐:start | end | center | stretch */
}

/* 单个网格项目的对齐 */
.grid-item-special {
  justify-self: end; /* 覆盖 justify-items */
  align-self: start; /* 覆盖 align-items */
}

2. 嵌套网格

.outer-grid {
  display: grid;
  grid-template-columns: 1fr 2fr;
  gap: 20px;
}

.nested-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-template-rows: repeat(3, 80px);
  gap: 10px;
}

3. 子网格(Subgrid)

/* 注意:subgrid 支持有限,主要在 Firefox 中 */
.parent-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(3, 100px);
  gap: 20px;
}

.subgrid-item {
  grid-column: 2 / 4;
  grid-row: 1 / 3;

  display: grid;
  grid-template-columns: subgrid; /* 继承父网格的列 */
  grid-template-rows: subgrid; /* 继承父网格的行 */
}

实际应用案例

1. 卡片网格布局

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

.card {
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  overflow: hidden;
  transition: transform 0.2s ease;
}

.card:hover {
  transform: translateY(-4px);
}

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

.card-content {
  padding: 20px;
}

/* 特殊卡片占据更多空间 */
.card.featured {
  grid-column: span 2;
}

@media (max-width: 768px) {
  .card.featured {
    grid-column: span 1; /* 移动端取消跨列 */
  }
}

2. 复杂的杂志布局

.magazine-layout {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  grid-template-rows: repeat(8, 100px);
  gap: 16px;
  max-width: 1200px;
  margin: 0 auto;
}

.hero-article {
  grid-column: 1 / 8;
  grid-row: 1 / 5;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  padding: 32px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}

.side-article-1 {
  grid-column: 8 / 13;
  grid-row: 1 / 3;
}

.side-article-2 {
  grid-column: 8 / 13;
  grid-row: 3 / 5;
}

.bottom-article-1 {
  grid-column: 1 / 5;
  grid-row: 5 / 7;
}

.bottom-article-2 {
  grid-column: 5 / 9;
  grid-row: 5 / 7;
}

.bottom-article-3 {
  grid-column: 9 / 13;
  grid-row: 5 / 7;
}

.ad-space {
  grid-column: 1 / 13;
  grid-row: 7 / 9;
  background: #f0f0f0;
  display: flex;
  align-items: center;
  justify-content: center;
}

3. 仪表板布局

.dashboard {
  display: grid;
  grid-template-columns: 250px 1fr;
  grid-template-rows: 60px 1fr;
  grid-template-areas:
    'sidebar header'
    'sidebar main';
  height: 100vh;
  gap: 0;
}

.dashboard-header {
  grid-area: header;
  background: white;
  border-bottom: 1px solid #e0e0e0;
  display: flex;
  align-items: center;
  padding: 0 24px;
}

.dashboard-sidebar {
  grid-area: sidebar;
  background: #2c3e50;
  color: white;
  padding: 24px 0;
}

.dashboard-main {
  grid-area: main;
  background: #f8f9fa;
  padding: 24px;
  overflow-y: auto;

  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  grid-auto-rows: min-content;
  gap: 24px;
  align-content: start;
}

.widget {
  background: white;
  border-radius: 8px;
  padding: 24px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.widget.large {
  grid-column: span 2;
}

.widget.tall {
  grid-row: span 2;
}

/* 响应式调整 */
@media (max-width: 768px) {
  .dashboard {
    grid-template-columns: 1fr;
    grid-template-rows: 60px auto 1fr;
    grid-template-areas:
      'header'
      'sidebar'
      'main';
  }

  .dashboard-sidebar {
    max-height: 200px;
    overflow-y: auto;
  }

  .widget.large,
  .widget.tall {
    grid-column: span 1;
    grid-row: span 1;
  }
}

Grid 与 Flexbox 的结合

.hybrid-layout {
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
}

.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 24px;
  background: white;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.main-content {
  display: grid;
  grid-template-columns: 250px 1fr;
  gap: 24px;
  padding: 24px;
}

.content-area {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.article-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 20px;
}

.footer {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 24px;
  background: #f8f9fa;
  border-top: 1px solid #e0e0e0;
}

性能优化建议

1. 避免不必要的重排

/* ✅ 好的做法:使用 transform 而不是改变 grid 属性 */
.grid-item {
  transition: transform 0.3s ease;
}

.grid-item:hover {
  transform: scale(1.05);
}

/* ❌ 避免:频繁改变 grid 属性 */
.grid-item:hover {
  grid-column: span 2; /* 会导致整个网格重新计算 */
}

2. 合理使用 will-change

.animated-grid-item {
  will-change: transform;
  transition: transform 0.3s ease;
}

.animated-grid-item:hover {
  transform: translateY(-8px);
}

/* 动画结束后移除 will-change */
.animated-grid-item.animation-complete {
  will-change: auto;
}

总结

CSS Grid 为现代网页布局提供了强大而灵活的解决方案:

  1. 二维布局:同时控制行和列
  2. 灵活的尺寸单位:fr、auto、minmax() 等
  3. 强大的对齐能力:多种对齐选项
  4. 响应式友好:auto-fit、auto-fill 等特性
  5. 语义化布局:grid-template-areas 提供直观的布局定义

掌握 CSS Grid,你就能创建出复杂而优雅的网页布局!


CSS Grid 是现代前端开发的必备技能,值得深入学习和实践。