返回首页

介绍一下 Grid 网格布局

问题解析

Grid 布局是 CSS 最强大的二维布局系统,能够同时处理行和列。面试考察这个问题,是想要了解候选人是否掌握现代 CSS 布局技术,以及能否利用 Grid 解决复杂布局问题。

什么是 Grid 布局

Grid 布局(网格布局) 是一个二维的布局方式,由纵横相交的两组网格线形成的框架性布局结构,能够同时处理行与列。

与 Flexbox(一维布局)的区别:

  • Flexbox:单一方向,行
  • Grid:两个方向,行

基础概念

网格线(Grid Lines)

划分网格的线,从 1 开始编号:

|    |    |    |    |
1    2    3    4    5  ← 列线
---------------------
|    |    |    |    | 1
---------------------
|    |    |    |    | 2
---------------------
|    |    |    |    | 3
---------------------
        行线

网格轨道(Grid Tracks)

两条网格线之间的空间,即行或列。

网格单元(Grid Cell)

最小的单位,一个"格子"。

网格区域(Grid Area)

由多个网格单元组成的矩形区域。

容器属性

1. 定义 Grid

.container {
  display: grid;           /* 块级网格 */
  display: inline-grid;    /* 行内网格 */
}

2. 定义行列

.container {
  /* 三列,固定宽度 */
  grid-template-columns: 200px 200px 200px;

  /* 两行,固定高度 */
  grid-template-rows: 100px 200px;

  /* 自动填充 */
  grid-template-columns: repeat(3, 200px);
  grid-template-rows: repeat(2, 100px);

  /* 混合单位 */
  grid-template-columns: 200px 1fr 2fr;
}

repeat() 函数

.container {
  /* repeat(次数, 值) */
  grid-template-columns: repeat(4, 1fr);

  /* 自动填充 */
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));

  /* 自动适应 */
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}

minmax() 函数

.container {
  /* 最小 200px,最大 1fr */
  grid-template-columns: minmax(200px, 1fr) 1fr 1fr;
}

3. 网格间隙

.container {
  /* 行列间隙相同 */
  gap: 20px;

  /* 分别设置 */
  row-gap: 20px;
  column-gap: 30px;

  /* 旧语法(已废弃) */
  grid-gap: 20px;
  grid-row-gap: 20px;
  grid-column-gap: 30px;
}

4. 定义网格区域

.container {
  grid-template-areas:
    "header header header"
    "sidebar main main"
    "footer footer footer";
}

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

5. 网格流方向

.container {
  grid-auto-flow: row;       /* 默认,先行后列 */
  grid-auto-flow: column;    /* 先列后行 */
  grid-auto-flow: row dense; /* 填充空白区域 */
}

6. 对齐方式

.container {
  /* 单元格内容对齐 */
  justify-items: start | end | center | stretch;  /* 水平 */
  align-items: start | end | center | stretch;     /* 垂直 */
  place-items: center;                            /* 简写 */

  /* 整个内容区域对齐 */
  justify-content: start | end | center | stretch | space-around | space-between | space-evenly;
  align-content: start | end | center | stretch | space-around | space-between | space-evenly;
  place-content: center;
}

7. 隐式网格

当项目超出定义的网格时:

.container {
  grid-auto-rows: 100px;     /* 隐式行高 */
  grid-auto-columns: 200px;  /* 隐式列宽 */
}

项目属性

1. 网格线定位

.item {
  /* 列线 2 到 4 */
  grid-column-start: 2;
  grid-column-end: 4;

  /* 简写 */
  grid-column: 2 / 4;
  grid-column: 2 / span 2;   /* 从 2 开始,跨 2 格 */

  /* 行线 */
  grid-row-start: 1;
  grid-row-end: 3;
  grid-row: 1 / 3;

  /* 合并简写 */
  grid-area: 1 / 2 / 3 / 4;   /* 行开始 / 列开始 / 行结束 / 列结束 */
}

2. 命名区域定位

.item {
  grid-area: header;
}

3. 单独对齐

.item {
  justify-self: center;   /* 水平居中 */
  align-self: center;     /* 垂直居中 */
  place-self: center;     /* 同时设置 */
}

实用布局示例

经典布局

.layout {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-rows: 60px 1fr 60px;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
  min-height: 100vh;
  gap: 20px;
}

.header { grid-area: header; background: #333; color: white; }
.sidebar { grid-area: sidebar; background: #f0f0f0; }
.main { grid-area: main; }
.footer { grid-area: footer; background: #333; color: white; }

响应式网格

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

/* 无需媒体查询,自动适应容器宽度 */

圣杯布局

.holy-grail {
  display: grid;
  grid-template-columns: 200px 1fr 200px;
  gap: 20px;
}

@media (max-width: 768px) {
  .holy-grail {
    grid-template-columns: 1fr;
  }
}

不规则布局

.masonry {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 100px;
  gap: 10px;
}

.item-1 {
  grid-column: span 2;
  grid-row: span 2;
}

.item-2 {
  grid-row: span 2;
}

Grid vs Flexbox

特性 Flexbox Grid
维度 一维(行或列) 二维(行和列)
适用场景 组件内部布局、导航栏 页面整体布局、复杂网格
内容驱动 是(由内容决定尺寸) 否(由网格决定尺寸)
间隙 gap(较新支持) gap(原生支持)
浏览器支持 很好 现代浏览器

协作使用

.page {
  display: grid;           /* Grid 做整体布局 */
}

.card {
  display: flex;           /* Flexbox 做卡片内部布局 */
  flex-direction: column;
}

高级特性

subgrid(子网格)

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

.child {
  display: grid;
  grid-template-columns: subgrid;   /* 继承父网格的列 */
}

网格命名线

.container {
  grid-template-columns:
    [sidebar-start] 200px
    [sidebar-end main-start] 1fr
    [main-end];
}

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

最佳实践

/* 1. 使用 fr 单位替代百分比 */
.container {
  grid-template-columns: 1fr 2fr 1fr;  /* 比例 1:2:1 */
}

/* 2. 响应式无需媒体查询 */
.responsive {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}

/* 3. 使用 grid-area 提高可读性 */
.container {
  grid-template-areas:
    "header header"
    "nav    content"
    "footer footer";
}

/* 4. 回退方案 */
.container {
  display: flex;
  flex-wrap: wrap;
}

@supports (display: grid) {
  .container {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
  }
}

面试要点

  1. 能够说出 Grid 和 Flexbox 的主要区别
  2. 能够写出常用的网格布局代码
  3. 理解 fr 单位和 auto-fit/auto-fill 的区别
  4. 知道如何使用 grid-template-areas 定义布局
  5. 了解 Grid 的兼容性情况和回退方案
  6. 能够用 Grid 实现常见的两栏、三栏、网格布局