网格布局
CSS网格布局
概述
CSS 网格布局(Grid Layout)是 CSS 中最强大的布局系统,它提供了一个基于二维网格的布局系统,使开发者能够创建复杂而灵活的页面布局。与一维布局系统(如弹性盒布局)不同,网格布局允许我们同时控制行和列,从而实现更加精确的元素定位和对齐。本文将深入探讨 CSS 网格布局的核心概念、属性用法、常见应用场景以及高级技巧,帮助您掌握这一现代 CSS 布局技术。
目录
基本概念
网格布局的核心思想
网格布局的核心思想是将页面划分为一个个网格单元,然后通过控制这些网格单元的大小、位置和内容,实现复杂的页面布局。网格布局特别适合创建整体页面结构、复杂的表格式布局以及需要精确对齐的设计。
网格容器与网格项目
网格布局包含两个核心概念:
- 网格容器(Grid Container):通过设置
display: grid
或display: inline-grid
创建的父元素 - 网格项目(Grid Items):网格容器的直接子元素
<div class="grid-container"> <!-- 网格容器 -->
<div class="grid-item">1</div> <!-- 网格项目 -->
<div class="grid-item">2</div> <!-- 网格项目 -->
<div class="grid-item">3</div> <!-- 网格项目 -->
</div>
.grid-container {
display: grid; /* 创建网格容器 */
}
网格线、网格单元、网格区域
网格布局中的几个重要概念:
- 网格线(Grid Lines):构成网格结构的水平线和垂直线
- 网格单元(Grid Cell):网格中的最小单位,由四条网格线围成的区域
- 网格区域(Grid Area):由一个或多个网格单元组成的矩形区域
- 网格轨道(Grid Track):两条相邻网格线之间的空间,即行或列

容器属性
display
创建网格容器的基本属性:
.grid-container {
display: grid; /* 创建块级网格容器 */
/* 或 */
display: inline-grid; /* 创建内联级网格容器 */
}
grid-template-columns 和 grid-template-rows
定义网格的列和行:
.grid-container {
/* 定义三列,宽度分别为 100px、1fr 和 2fr */
grid-template-columns: 100px 1fr 2fr;
/* 定义两行,高度分别为 100px 和 200px */
grid-template-rows: 100px 200px;
}
fr 单位
fr
是一个特殊单位,表示剩余空间的一部分(fraction):
.grid-container {
grid-template-columns: 1fr 2fr 1fr; /* 三列,按 1:2:1 的比例分配空间 */
}
repeat() 函数
使用 repeat()
函数可以简化重复值的写法:
.grid-container {
/* 创建 4 列,每列宽度为 100px */
grid-template-columns: repeat(4, 100px);
/* 创建 3 列,宽度分别为 1fr、2fr、1fr,然后重复两次 */
grid-template-columns: repeat(2, 1fr 2fr 1fr);
}
minmax() 函数
使用 minmax()
函数可以设置网格轨道的最小和最大尺寸:
.grid-container {
/* 列宽最小 100px,最大 1fr */
grid-template-columns: repeat(3, minmax(100px, 1fr));
}
auto-fill 和 auto-fit
使用 auto-fill
和 auto-fit
可以创建响应式网格:
.grid-container {
/* 根据容器宽度,自动填充尽可能多的列,每列宽度至少 200px */
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
/* 类似 auto-fill,但会拉伸现有列填满容器 */
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
grid-template-areas
使用命名的网格区域定义布局:
.grid-container {
grid-template-areas:
"header header header"
"sidebar content content"
"footer footer footer";
grid-template-columns: 1fr 3fr 1fr;
grid-template-rows: auto 1fr auto;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.footer { grid-area: footer; }
grid-template
grid-template-columns
、grid-template-rows
和 grid-template-areas
的简写属性:
.grid-container {
grid-template:
"header header header" auto
"sidebar content content" 1fr
"footer footer footer" auto
/ 1fr 3fr 1fr;
}
grid-column-gap、grid-row-gap 和 grid-gap
设置网格线的宽度(即列间距和行间距):
.grid-container {
grid-column-gap: 20px; /* 列间距 */
grid-row-gap: 10px; /* 行间距 */
/* 或使用简写形式 */
grid-gap: 10px 20px; /* 行间距 列间距 */
grid-gap: 15px; /* 行列间距相同 */
}
注:现代浏览器也支持不带
grid-
前缀的属性名:column-gap
、row-gap
和gap
。
justify-items 和 align-items
控制网格项目在网格单元内的水平和垂直对齐方式:
.grid-container {
justify-items: start | end | center | stretch; /* 水平对齐 */
align-items: start | end | center | stretch; /* 垂直对齐 */
}
place-items
justify-items
和 align-items
的简写属性:
.grid-container {
place-items: center; /* 水平垂直居中 */
place-items: start end; /* 水平靠左,垂直靠下 */
}
justify-content 和 align-content
当网格总大小小于容器大小时,控制网格在容器内的对齐方式:
.grid-container {
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
justify-content
和 align-content
的简写属性:
.grid-container {
place-content: center; /* 水平垂直居中 */
place-content: space-between center; /* 水平均匀分布,垂直居中 */
}
grid-auto-columns 和 grid-auto-rows
设置自动生成的网格轨道(隐式网格轨道)的大小:
.grid-container {
grid-auto-columns: 100px; /* 自动生成的列宽为 100px */
grid-auto-rows: minmax(100px, auto); /* 自动生成的行高最小为 100px */
}
grid-auto-flow
控制自动放置算法的工作方式:
.grid-container {
grid-auto-flow: row; /* 默认值,先填满行,再换到下一行 */
grid-auto-flow: column; /* 先填满列,再换到下一列 */
grid-auto-flow: row dense; /* 尝试填满网格中的空隙 */
grid-auto-flow: column dense;
}
grid
所有网格属性的简写形式:
.grid-container {
grid: 100px 200px / 1fr 2fr; /* 行高 / 列宽 */
/* 或更复杂的形式 */
grid:
"header header" 100px
"sidebar content" auto
/ 1fr 3fr;
}
项目属性
grid-column-start、grid-column-end、grid-row-start 和 grid-row-end
指定网格项目的位置:
.grid-item {
grid-column-start: 1; /* 从第1条列线开始 */
grid-column-end: 3; /* 到第3条列线结束 */
grid-row-start: 2; /* 从第2条行线开始 */
grid-row-end: 4; /* 到第4条行线结束 */
}
grid-column 和 grid-row
grid-column-start
/grid-column-end
和 grid-row-start
/grid-row-end
的简写形式:
.grid-item {
grid-column: 1 / 3; /* 从第1条列线到第3条列线 */
grid-row: 2 / 4; /* 从第2条行线到第4条行线 */
/* 或使用 span 关键字 */
grid-column: 1 / span 2; /* 从第1条列线开始,跨越2个列 */
grid-row: 2 / span 2; /* 从第2条行线开始,跨越2个行 */
}
grid-area
指定网格项目放置在哪个命名的网格区域,或者作为 grid-row-start
/grid-column-start
/grid-row-end
/grid-column-end
的简写:
.grid-item {
grid-area: header; /* 放置在名为 header 的网格区域 */
/* 或作为位置的简写 */
grid-area: 2 / 1 / 4 / 3; /* 行开始 / 列开始 / 行结束 / 列结束 */
}
justify-self 和 align-self
控制单个网格项目在网格单元内的水平和垂直对齐方式:
.grid-item {
justify-self: start | end | center | stretch; /* 水平对齐 */
align-self: start | end | center | stretch; /* 垂直对齐 */
}
place-self
justify-self
和 align-self
的简写属性:
.grid-item {
place-self: center; /* 水平垂直居中 */
place-self: start end; /* 水平靠左,垂直靠下 */
}
网格布局模型
显式网格与隐式网格
- 显式网格:通过
grid-template-columns
和grid-template-rows
明确定义的网格 - 隐式网格:当内容超出显式网格范围时,自动创建的网格轨道
.grid-container {
/* 显式网格:2行3列 */
grid-template-columns: repeat(3, 1fr);
grid-template-rows: 100px 100px;
/* 隐式网格的大小 */
grid-auto-rows: 100px;
}
网格线编号与命名
网格线默认从1开始编号,也可以给网格线命名:
.grid-container {
grid-template-columns: [start] 1fr [middle] 2fr [end];
grid-template-rows: [top] 100px [center] 100px [bottom];
}
.grid-item {
grid-column: start / end; /* 使用命名的网格线 */
grid-row: top / center;
}
网格区域的命名与使用
通过 grid-template-areas
命名网格区域:
.grid-container {
grid-template-areas:
"header header header"
"sidebar content content"
"footer footer footer";
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.footer { grid-area: footer; }
实际应用
经典布局模式
圣杯布局
.holy-grail {
display: grid;
grid-template-areas:
"header header header"
"nav content sidebar"
"footer footer footer";
grid-template-columns: 200px 1fr 200px;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
.header { grid-area: header; }
.nav { grid-area: nav; }
.content { grid-area: content; }
.sidebar { grid-area: sidebar; }
.footer { grid-area: footer; }
/* 响应式调整 */
@media (max-width: 768px) {
.holy-grail {
grid-template-areas:
"header"
"nav"
"content"
"sidebar"
"footer";
grid-template-columns: 1fr;
grid-template-rows: auto auto 1fr auto auto;
}
}
卡片网格布局
创建自适应的卡片网格:
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 20px;
padding: 20px;
}
.card {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
padding: 20px;
}
.card-featured {
grid-column: span 2;
grid-row: span 2;
}
杂志布局
创建类似杂志的复杂布局:
.magazine-layout {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(3, auto);
gap: 20px;
}
.headline {
grid-column: 1 / -1; /* 跨越所有列 */
grid-row: 1;
}
.main-story {
grid-column: 1 / 3;
grid-row: 2 / 4;
}
.secondary-story {
grid-column: 3 / 5;
grid-row: 2;
}
.sidebar {
grid-column: 3 / 5;
grid-row: 3;
}
常见UI组件
响应式导航栏
.navbar {
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center;
padding: 0 20px;
height: 60px;
background-color: #333;
color: white;
}
.logo { justify-self: start; }
.nav-links { justify-self: center; }
.user-actions { justify-self: end; }
/* 响应式调整 */
@media (max-width: 768px) {
.navbar {
grid-template-columns: 1fr;
grid-template-rows: auto auto auto;
height: auto;
padding: 10px 20px;
}
.logo, .nav-links, .user-actions {
justify-self: center;
margin: 5px 0;
}
}
图片画廊
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-auto-rows: 200px;
gap: 10px;
}
.gallery-item {
overflow: hidden;
position: relative;
}
.gallery-item img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s;
}
.gallery-item:hover img {
transform: scale(1.1);
}
.gallery-item.wide {
grid-column: span 2;
}
.gallery-item.tall {
grid-row: span 2;
}
.gallery-item.large {
grid-column: span 2;
grid-row: span 2;
}
布局技巧
自动填充与自动适应
使用 auto-fill
和 auto-fit
创建响应式布局:
/* auto-fill:尽可能创建更多列 */
.auto-fill-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 20px;
}
/* auto-fit:拉伸现有列填满容器 */
.auto-fit-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
}
网格中的居中对齐
在网格中实现元素的完美居中:
.center-in-grid {
display: grid;
place-items: center; /* 水平垂直居中 */
height: 100vh;
}
.center-item {
/* 不需要额外样式,自动居中 */
}
叠加元素
使用网格创建叠加效果:
.overlap-container {
display: grid;
grid-template: "stack" 300px / 1fr;
}
.overlap-container > * {
grid-area: stack; /* 所有子元素叠加在同一区域 */
}
.background { z-index: 1; }
.foreground { z-index: 2; }
高级技巧
网格与其他布局方法结合
网格与弹性盒结合
.grid-flex-combo {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.grid-item {
display: flex;
flex-direction: column;
justify-content: space-between;
}
.item-header {
display: flex;
justify-content: space-between;
align-items: center;
}
网格与定位结合
.grid-position-combo {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
position: relative;
}
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: grid;
place-items: center;
opacity: 0;
transition: opacity 0.3s;
}
.grid-position-combo:hover .overlay {
opacity: 1;
}
子网格(Subgrid)
子网格允许网格项目继承父网格的轨道定义:
.parent-grid {
display: grid;
grid-template-columns: repeat(9, 1fr);
gap: 10px;
}
.child-grid {
grid-column: 2 / 7;
display: grid;
grid-template-columns: subgrid; /* 继承父网格的列定义 */
gap: 5px;
}
注:子网格(subgrid)是较新的特性,目前并非所有浏览器都支持。
网格模板区域的动态变化
使用媒体查询动态改变网格布局:
.dashboard {
display: grid;
gap: 20px;
grid-template-areas:
"header header header"
"sidebar main main"
"sidebar stats stats";
grid-template-columns: 200px 1fr 1fr;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.stats { grid-area: stats; }
@media (max-width: 768px) {
.dashboard {
grid-template-areas:
"header header"
"main main"
"sidebar stats";
grid-template-columns: 1fr 1fr;
}
}
@media (max-width: 480px) {
.dashboard {
grid-template-areas:
"header"
"main"
"sidebar"
"stats";
grid-template-columns: 1fr;
}
}
网格中的动画
在网格布局中应用动画效果:
.animated-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 20px;
}
.grid-item {
transition: all 0.3s;
}
.grid-item:hover {
transform: translateY(-10px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
grid-column: span 2;
grid-row: span 2;
z-index: 1;
}
浏览器兼容性
现代浏览器支持
现代浏览器对网格布局的支持情况:
浏览器 | 版本支持 |
---|---|
Chrome | 57+ |
Firefox | 52+ |
Safari | 10.1+ |
Edge | 16+ |
IE | 不支持(IE10/11 支持旧版语法) |
兼容性问题
常见的兼容性问题及解决方案:
- IE 不支持网格布局:
/* 为不支持网格的浏览器提供回退方案 */
.grid-container {
display: flex;
flex-wrap: wrap;
}
.grid-item {
flex: 0 0 calc(33.33% - 20px);
margin: 10px;
}
/* 现代浏览器使用网格布局 */
@supports (display: grid) {
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.grid-item {
flex: none;
margin: 0;
}
}
- 使用特性检测:
/* 使用 @supports 检测网格布局支持 */
@supports (display: grid) {
.modern-layout {
display: grid;
/* 网格相关样式 */
}
}
@supports not (display: grid) {
.modern-layout {
display: flex;
/* 回退样式 */
}
}
- 使用 Autoprefixer:
在构建过程中使用 Autoprefixer 自动添加浏览器前缀,简化兼容性处理。
渐进增强策略
采用渐进增强策略,确保在不支持网格布局的浏览器中也能提供基本功能:
/* 基础样式(所有浏览器) */
.container {
max-width: 1200px;
margin: 0 auto;
}
.item {
float: left;
width: 100%;
padding: 10px;
box-sizing: border-box;
}
/* 中等屏幕(使用浮动布局) */
@media (min-width: 600px) {
.item {
width: 50%;
}
}
/* 大屏幕(使用网格布局) */
@supports (display: grid) {
@media (min-width: 900px) {
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.item {
width: auto;
float: none;
}
}
}
最佳实践
选择合适的网格布局方法
- 显式网格与隐式网格:
/* 显式定义所有网格轨道(更可控) */
.explicit-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 100px);
}
/* 只定义列,让行自动生成(更灵活) */
.implicit-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: minmax(100px, auto);
}
- 网格区域与网格线:
/* 使用网格区域(更直观) */
.area-based {
display: grid;
grid-template-areas:
"header header header"
"sidebar content content"
"footer footer footer";
}
/* 使用网格线(更精确) */
.line-based {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: auto 1fr auto;
}
.header {
grid-column: 1 / -1;
grid-row: 1;
}
避免常见陷阱
- 避免过度复杂的网格定义:
/* 不推荐:过于复杂的网格定义 */
.complex-grid {
grid-template-columns: 100px minmax(200px, 1fr) 2fr minmax(100px, 200px);
grid-template-rows: [start] 100px [header-end] repeat(2, [row-start] 200px [row-end]) auto;
}
/* 推荐:简化的网格定义 */
.simple-grid {
grid-template-columns: 100px 1fr 2fr 100px;
grid-template-rows: 100px repeat(2, 200px) auto;
}
- 注意网格项目的溢出:
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.grid-item {
min-width: 0; /* 防止内容溢出 */
overflow: hidden; /* 处理溢出内容 */
}
性能考虑
- 避免频繁改变网格结构:
/* 不推荐:频繁改变网格结构 */
.item:hover {
grid-template-columns: 1fr 2fr 1fr; /* 悬停时改变网格结构 */
}
/* 推荐:改变项目而非网格结构 */
.item:hover {
grid-column: span 2; /* 只改变项目的位置 */
}
- 使用
will-change
提示浏览器:
.animated-grid-item {
will-change: grid-column, grid-row;
transition: grid-column 0.3s, grid-row 0.3s;
}
响应式设计
- 移动优先设计:
.responsive-grid {
display: grid;
grid-template-columns: 1fr; /* 移动设备默认单列 */
}
@media (min-width: 600px) {
.responsive-grid {
grid-template-columns: repeat(2, 1fr); /* 平板设备两列 */
}
}
@media (min-width: 900px) {
.responsive-grid {
grid-template-columns: repeat(3, 1fr); /* 桌面设备三列 */
}
}
@media (min-width: 1200px) {
.responsive-grid {
grid-template-columns: repeat(4, 1fr); /* 大屏设备四列 */
}
}
- 使用
minmax
和auto-fit
实现自适应:
.auto-responsive-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
/* 无需媒体查询,自动适应各种屏幕尺寸 */
}
- 结合 CSS 变量实现灵活的响应式设计:
:root {
--grid-columns-small: 1;
--grid-columns-medium: 2;
--grid-columns-large: 3;
--grid-columns-xlarge: 4;
}
.variable-grid {
display: grid;
grid-template-columns: repeat(var(--grid-columns-small), 1fr);
gap: 20px;
}
@media (min-width: 600px) {
.variable-grid {
grid-template-columns: repeat(var(--grid-columns-medium), 1fr);
}
}
@media (min-width: 900px) {
.variable-grid {
grid-template-columns: repeat(var(--grid-columns-large), 1fr);
}
}
@media (min-width: 1200px) {
.variable-grid {
grid-template-columns: repeat(var(--grid-columns-xlarge), 1fr);
}
}
可访问性考虑
- 保持合理的源代码顺序:
/* 网格布局可以改变视觉顺序,但要确保源代码顺序对屏幕阅读器友好 */
.grid-container {
display: grid;
grid-template-areas:
"header header"
"main sidebar"
"footer footer";
}
/* HTML 结构应该遵循逻辑顺序 */
<!--
<header>...</header>
<main>...</main>
<aside>...</aside>
<footer>...</footer>
-->
- 使用
order
属性时注意可访问性:
/* 使用 order 改变视觉顺序时要谨慎,它不会改变键盘导航或屏幕阅读器的顺序 */
.first-visually {
order: -1; /* 视觉上排在最前面,但不影响源代码顺序 */
}
参考资源
- MDN Web Docs: CSS 网格布局
- CSS-Tricks: A Complete Guide to Grid
- Grid by Example - Rachel Andrew 的网格布局示例集
- Grid Garden - 学习网格布局的游戏
- Can I Use: CSS Grid - 浏览器兼容性查询
- Jen Simmons: Layout Land - 关于网格布局的视频教程
- W3C CSS Grid Layout Module Level 1 - 官方规范
- Wes Bos: CSS Grid Course - 免费的网格布局课程
- Smashing Magazine: CSS Grid 实践指南
- Designing with Grid - 使用网格设计的实用指南