CSS Grid 布局从入门到精通

掌握二维布局,告别浮动和定位 hack

CSS Grid 是 CSS 有史以来最强大的布局系统。与 Flexbox 的一维布局不同,Grid 可以同时控制行和列两个维度,是实现复杂页面布局的终极解决方案。2024 年,Grid 在全球浏览器的支持率已超过 97%,完全可以放心使用。本文从基础到高级,带你全面掌握 CSS Grid。

1. 基础概念:容器与项目

Grid 布局由容器(grid container)和项目(grid items)组成。容器是设置了 display: grid 的元素,其直接子元素自动成为 grid 项目。

.container {
    display: grid;
    /* 定义列:三列等宽 */
    grid-template-columns: 1fr 1fr 1fr;
    /* 定义行:两行,第一行100px,第二行自适应 */
    grid-template-rows: 100px auto;
    /* 间距 */
    gap: 20px;
}

.item {
    background: #4F46E5;
    border-radius: 8px;
}

fr 是 Grid 引入的新单位,表示"剩余空间的份数"。上面的例子中,三列各占 1fr,意思是把容器宽度分成三份,每列占一份。

grid-template-columns 的多种写法

/* 固定像素 */
grid-template-columns: 200px 200px 200px;

/* 混合单位 */
grid-template-columns: 200px 1fr 2fr;
/* 第一列200px,剩余空间按1:2分配给第二三列 */

/* repeat() 函数 */
grid-template-columns: repeat(3, 1fr);
/* 等同于 1fr 1fr 1fr */

/* 带最小最大值 */
grid-template-columns: repeat(3, minmax(200px, 1fr));
/* 每列最小200px,最大1fr */

/* auto-fill vs auto-fit */
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
/* auto-fill: 尽量多放列,即使列是空的 */
/* auto-fit: 空列会被折叠,已有的列会展开填满 */

2. 项目定位:用行列线定位元素

Grid 中每个单元格都有行列线编号,可以精确控制项目占据的位置和跨度。

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

/* 占两列宽 */
.item-wide {
    grid-column: 1 / 3;  /* 从第1条列线到第3条列线 */
    /* 或:grid-column: span 2;  跨2列 */
}

/* 占两行高 */
.item-tall {
    grid-row: 1 / 3;     /* 从第1条行线到第3条行线 */
}

/* 指定具体位置 */
.item-specific {
    grid-column: 2 / 4;
    grid-row: 2 / 4;
}

/* 简写 */
.item {
    grid-area: 1 / 2 / 3 / 4;
    /* row-start / column-start / row-end / column-end */
}

3. 区域命名:更语义化的布局

当布局复杂时,行列线编号难以维护。Grid 提供了命名区域的方式,让布局代码读起来就像在画蓝图。

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

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

这种写法的好处是一眼就能看出页面结构。配合媒体查询,可以轻松实现响应式布局——只需在不同断点下重新定义 grid-template-areas

@media (max-width: 768px) {
    .layout {
        grid-template-columns: 1fr;
        grid-template-areas:
            "header"
            "main"
            "sidebar"
            "right"
            "footer";
    }
}

4. 对齐方式:对齐容器内的所有项目

Grid 有两套对齐属性:一组控制内容在单元格内的对齐,一组控制整个网格在容器中的对齐。

.container {
    display: grid;
    grid-template-columns: repeat(3, 100px);
    grid-template-rows: repeat(2, 100px);
    gap: 10px;

    /* 单元格内对齐(项目级别) */
    justify-items: center;  /* 水平:start | end | center | stretch */
    align-items: center;    /* 垂直:start | end | center | stretch */
    place-items: center;    /* 简写 */

    /* 整个网格在容器中的对齐(容器级别) */
    justify-content: center; /* 水平 */
    align-content: center;   /* 垂直 */
}

记忆方法:*-items 控制单元格里的项目怎么放,*-content 控制整个网格在容器里怎么放。当容器比网格大时,*-content 才有效果。

5. 实战:响应式卡片网格

这是 Grid 最经典的应用场景——一行代码实现自适应的卡片网格,不需要媒体查询:

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

.card {
    background: white;
    border-radius: 12px;
    padding: 24px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}

这段代码的精妙之处:auto-fit 让浏览器自动计算一行能放几列,minmax(280px, 1fr) 保证每列至少 280px 宽,空间够的时候等分。容器变窄时列数自动减少,变宽时列数自动增加,完全响应式。

6. Grid vs Flexbox:什么时候用哪个?

这是最常见的问题。简单的判断标准:

在实际项目中,两者经常配合使用:Grid 负责页面整体骨架,Flexbox 负责组件内部的细节对齐。搭配得当,几乎没有摆不平的布局。

7. 调试技巧

Chrome DevTools 对 Grid 有非常棒的调试支持:在 Elements 面板找到 grid 容器,点击 grid 标签旁的徽章,页面上会显示网格线、行号、列号和区域名称。还可以在 Layout 面板中调整显示选项,帮助你理解复杂的 Grid 布局。

7. 高级特性:子网格与 masonry

Subgrid(子网格)

子网格是 Grid 最期待的特性之一。它允许嵌套的 grid 容器继承父容器的行列定义,实现真正的嵌套对齐。在 subgrid 之前,嵌套 Grid 的对齐只能靠手动计算,非常麻烦。

.parent {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-template-rows: auto auto;
    gap: 20px;
}

.child {
    grid-column: span 3;
    display: grid;
    /* 子网格:继承父级的列定义 */
    grid-template-columns: subgrid;
    /* 这样子元素会和父级网格对齐 */
}

Subgrid 在 Safari 16+ 和 Firefox 71+ 中已支持,Chrome 也在积极开发中。对于需要精确对齐的卡片布局,subgrid 将是游戏规则改变者。

Masonry 布局

Masonry(瀑布流)布局是 Pinterest 带火的一种布局方式——元素高度不同,像砌墙一样错落排列。过去实现瀑布流需要 JavaScript 库(如 Masonry.js),现在 Grid 的 masonry 值可以原生实现。

.masonry {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    grid-template-rows: masonry;  /* 瀑布流 */
    gap: 16px;
}

目前 masonry 还在实验阶段,只有 Firefox 支持。在生产环境中,还是需要用 CSS columns 或 JavaScript 来实现瀑布流布局。

8. 常见布局模式

圣杯布局

经典的三栏布局——两侧边栏固定宽度,中间内容区自适应。用 Grid 实现极其简单:

.holy-grail {
    display: grid;
    grid-template-columns: 200px 1fr 200px;
    grid-template-rows: auto 1fr auto;
    grid-template-areas:
        "header header header"
        "left   main   right"
        "footer footer footer";
    min-height: 100vh;
}

仪表盘布局

后台管理系统常见的侧边栏 + 顶部导航 + 内容区布局:

.dashboard {
    display: grid;
    grid-template-columns: 240px 1fr;
    grid-template-rows: 60px 1fr;
    grid-template-areas:
        "sidebar header"
        "sidebar main";
    height: 100vh;
}

.sidebar { grid-area: sidebar; overflow-y: auto; }
.header  { grid-area: header; }
.main    { grid-area: main; overflow-y: auto; }

9. 浏览器兼容性与降级方案

截至 2024 年,CSS Grid 在全球浏览器的支持率超过 97%,IE 11 是最后一个不支持的主流浏览器。如果你的项目还需要兼容 IE,可以用 @supports 做渐进增强:

/* 降级方案:用 float 或 flexbox */
.grid-container {
    display: flex;
    flex-wrap: wrap;
}

/* 支持 Grid 的浏览器使用 Grid */
@supports (display: grid) {
    .grid-container {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
        gap: 24px;
    }
}

不过到了 2026 年,IE 已经彻底退出历史舞台,Grid 可以放心大胆地使用。甚至连一些较新的特性(如 aspect-ratio、clamp、container queries)都有很高的支持率。

10. 学习资源推荐

想要深入学习 CSS Grid,以下资源值得推荐:

学习 Grid 的最好方式是动手实践。下次遇到布局需求时,强迫自己用 Grid 来实现,哪怕一开始写得慢。用不了一周,你就会发现 Grid 已经融入了你的肌肉记忆,再也回不到 float 和 position 的时代了。

11. 命名网格线

除了用数字引用网格线,还可以给网格线命名,让布局代码更语义化。

.container {
    display: grid;
    grid-template-columns:
        [sidebar-start] 240px
        [sidebar-end main-start] 1fr
        [main-end];
    grid-template-rows:
        [header-start] 60px
        [header-end content-start] 1fr
        [content-end footer-start] auto
        [footer-end];
}

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

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

命名网格线在复杂布局中特别有用。配合 -start-end 后缀,还可以用区域名直接引用:

/* 如果有 sidebar-start 和 sidebar-end,就可以直接写 */
.sidebar {
    grid-column: sidebar;  /* 自动对应 sidebar-start 到 sidebar-end */
}

12. min()、max()、clamp() 与 Grid

CSS 的数学函数和 Grid 搭配使用,可以实现非常灵活的响应式布局。

.container {
    display: grid;
    /* 列宽在 200px 到 1fr 之间,不超过 300px */
    grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
    gap: clamp(12px, 2vw, 24px);  /* 间距响应式变化 */
}

/* clamp(min, preferred, max) 函数 */
/* 间距随视口宽度变化,但不小于 12px,不大于 24px */
gap: clamp(12px, 2vw, 24px);

这些 CSS 函数可以替代很多之前需要媒体查询才能实现的响应式效果,让代码更简洁。特别是 clamp(),在流体排版(fluid typography)和响应式间距中非常实用。

13. 常见坑点与解决方案

使用 Grid 时容易遇到一些意想不到的问题,这里列出几个最常见的坑和解决方案。

grid 项目内容溢出

Grid 项目默认最小宽度是内容宽度(min-width: auto),这可能导致网格项目超出预期宽度。解决方案是设置 min-width: 0 或使用 minmax(0, 1fr)

/* 防止内容溢出网格 */
.grid-item {
    min-width: 0;
    overflow: hidden;  /* 或 auto */
}

/* 列定义时使用 minmax(0, 1fr) 而不只是 1fr */
grid-template-columns: repeat(3, minmax(0, 1fr));

gap 的兼容性

Grid 的 gap 属性在较新的浏览器中才支持(Chrome 66+)。如果需要兼容老版本浏览器,可以用 padding + 负 margin 的方式模拟间距,或者用 PostCSS 的 gap 插件做降级。

总之,Grid 并不难,难的是从传统布局思维中跳出来。当你真正用 Grid 的方式思考布局时,会发现曾经复杂的页面布局,现在几行代码就能搞定。