Appearance
07|CSS Grid 布局与响应式
Flexbox 擅长一维布局(一行或一列),但面对二维布局——同时控制行和列——就显得笨拙。CSS Grid(网格布局)专门为二维布局设计:定义好行和列的轨道,再把元素放进指定的格子里。配合媒体查询,Grid 也是实现响应式页面的核心工具。
一、启用 Grid
css
.container {
display: grid;
grid-template-columns: 200px 200px 200px; /* 三列,每列 200px */
grid-template-rows: 100px 100px; /* 两行,每行 100px */
gap: 16px; /* 行列间距 */
}直接子元素会自动按顺序填入网格单元。上面定义了一个 3 列 × 2 行的网格,共 6 个单元格。
二、定义列和行
固定尺寸
css
.container {
display: grid;
grid-template-columns: 200px 200px 200px;
}三列,每列固定 200px。如果容器宽度超过 600px,右侧会出现空白;如果小于 600px,列会溢出。
比例分配(fr)
css
.container {
display: grid;
grid-template-columns: 1fr 2fr 1fr; /* 左:中:右 = 1:2:1 */
}fr(fraction,分数)表示可用空间的比例。总空间减去固定尺寸和 gap 后,按 fr 值分配。上面中间列的宽度是左右列的两倍。
css
/* 侧边栏固定,主内容自适应 */
.container {
display: grid;
grid-template-columns: 240px 1fr;
}repeat 简写
css
.container {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 等同于 1fr 1fr 1fr */
}第一个参数是重复次数,第二个参数是轨道尺寸。
css
/* 自动填充:每列最小 200px,能放多少放多少 */
.container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 16px;
}auto-fill 会根据容器宽度自动计算能放多少列。minmax(200px, 1fr) 表示每列至少 200px,剩余空间平均分配。
三、放置元素
默认情况下,子元素按文档顺序依次填入网格。也可以显式指定位置:
css
.item-a {
grid-column: 1 / 3; /* 从第 1 条列线到第 3 条列线,占据两列 */
grid-row: 1 / 2; /* 第 1 行 */
}
.item-b {
grid-column: 3 / 4; /* 第 3 列 */
grid-row: 1 / 3; /* 从第 1 条行线到第 3 条行线,占据两行 */
}网格线编号从 1 开始。3 列有 4 条列线,2 行有 3 条行线。
也可以用 span 表示跨多少轨道:
css
.item-wide {
grid-column: span 2; /* 从当前位置开始,跨两列 */
}命名区域
对于复杂布局,可以给区域命名:
css
.container {
display: grid;
grid-template-columns: 200px 1fr 200px;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
gap: 16px;
}
.header { grid-area: header; }
.nav { grid-area: nav; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }grid-template-areas 用字符串直观描述布局结构。同一行内用空格分隔,. 表示空单元格。
css
/* 空出右上角 */
grid-template-areas:
"header header ."
"nav main aside"
"footer footer footer";四、对齐
Grid 的对齐属性与 Flexbox 类似,但作用于网格轨道:
容器级别
css
.container {
display: grid;
justify-content: center; /* 整个网格在容器中水平居中 */
align-content: center; /* 整个网格在容器中垂直居中 */
}单元格级别
css
.container {
display: grid;
justify-items: center; /* 所有单元格内容水平居中 */
align-items: center; /* 所有单元格内容垂直居中 */
}也可以对单个项设置:
css
.item {
justify-self: end; /* 这个项在单元格内靠右 */
align-self: center; /* 这个项在单元格内垂直居中 */
}五、响应式与媒体查询
响应式设计的核心是:同一套 HTML,在不同屏幕尺寸下呈现不同的布局和样式。媒体查询是实现这一能力的 CSS 机制。
基本语法
css
/* 默认样式(移动端优先) */
.container {
display: grid;
grid-template-columns: 1fr;
gap: 12px;
}
/* 屏幕宽度 >= 768px 时 */
@media (min-width: 768px) {
.container {
grid-template-columns: repeat(2, 1fr);
gap: 16px;
}
}
/* 屏幕宽度 >= 1024px 时 */
@media (min-width: 1024px) {
.container {
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
}| 断点 | 宽度 | 典型设备 |
|---|---|---|
| 无 | < 768px | 手机 |
sm | ≥ 768px | 平板竖屏 |
md | ≥ 1024px | 平板横屏/小桌面 |
lg | ≥ 1280px | 桌面 |
xl | ≥ 1536px | 大桌面 |
上面的数值是常见约定,实际项目中可以根据内容和设计稿调整。
移动优先 vs 桌面优先
移动优先(推荐):先写移动端样式,再用 min-width 媒体查询逐步增强:
css
/* 基础:单列 */
.grid { grid-template-columns: 1fr; }
/* 平板:两列 */
@media (min-width: 768px) {
.grid { grid-template-columns: repeat(2, 1fr); }
}
/* 桌面:三列 */
@media (min-width: 1024px) {
.grid { grid-template-columns: repeat(3, 1fr); }
}桌面优先:先写桌面样式,再用 max-width 媒体查询降级:
css
/* 基础:三列 */
.grid { grid-template-columns: repeat(3, 1fr); }
/* 小屏幕:两列 */
@media (max-width: 1023px) {
.grid { grid-template-columns: repeat(2, 1fr); }
}
/* 手机:单列 */
@media (max-width: 767px) {
.grid { grid-template-columns: 1fr; }
}移动优先更符合现代开发习惯:手机用户通常网络更慢、设备性能更弱,优先加载和渲染移动端样式能提升首屏体验。此外,移动端样式通常更简单,代码量更少。
其他媒体特性
css
/* prefers-color-scheme: 检测系统深色模式 */
@media (prefers-color-scheme: dark) {
body {
background-color: #1a1a1a;
color: #e0e0e0;
}
}
/* 打印样式 */
@media print {
.no-print { display: none; }
body { font-size: 12pt; }
}六、viewport 设置
响应式页面需要在 head 中加入 viewport meta 标签:
html
<meta name="viewport" content="width=device-width, initial-scale=1.0">| 值 | 作用 |
|---|---|
width=device-width | 视口宽度等于设备屏幕宽度 |
initial-scale=1.0 | 初始缩放比例为 1 |
maximum-scale=1.0 | 禁止用户缩放(不建议,影响无障碍访问) |
缺少这个标签时,移动端浏览器会按桌面宽度(通常是 980px)渲染页面,导致文字过小、需要手动缩放。
七、常见场景
响应式卡片网格
css
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 16px;
}每列至少 280px,能放多少放多少。容器变宽时自动增加列数,变窄时减少——不需要媒体查询。
经典圣杯布局
css
.layout {
display: grid;
grid-template-columns: 240px 1fr 240px;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
min-height: 100vh;
gap: 16px;
}
@media (max-width: 1023px) {
.layout {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"nav"
"main"
"aside"
"footer";
}
}桌面端三栏,平板和手机端垂直堆叠。
八、常见错误
Grid 和 Flex 混用导致困惑
css
/* 错误:在 grid 项里又用 flex 做一维对齐,其实 align-self 就够了 */
.grid-item {
display: flex;
align-items: center;
}
/* 正确:直接用 grid 的对齐属性 */
.container {
display: grid;
align-items: center;
}忘记 viewport meta
页面在手机上显示为桌面版缩小效果,文字无法阅读。检查 head 中是否包含:
html
<meta name="viewport" content="width=device-width, initial-scale=1.0">固定宽度破坏响应式
css
/* 错误:在大屏幕上居中,在小屏幕上溢出 */
.container {
width: 1200px;
}
/* 正确:最大宽度限制,小屏幕自适应 */
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 16px;
}媒体查询断点过于细碎
css
/* 不建议:断点太多,维护困难 */
@media (min-width: 320px) { ... }
@media (min-width: 375px) { ... }
@media (min-width: 414px) { ... }
/* 建议:按内容自然断裂,通常 3~4 个断点足够 */
@media (min-width: 768px) { ... }
@media (min-width: 1024px) { ... }