CSS:Grid 二维布局

编辑文章

简介

CSS Grid布局是一个用于在网页上创建二维(行和列)布局系统的强大工具,它让你能像设计师一样轻松地划分区域、排列元素,是构建现代复杂网页界面的核心CSS模块。

语法

Grid布局通过为父容器(网格容器)和其子项(网格项目)设置一系列属性来工作。

容器属性

.grid-container {
  display: grid | inline-grid; /* 开启网格布局 */
  grid-template-columns: <track-size> ... | <line-name> <track-size> ...;
  grid-template-rows: <track-size> ... | <line-name> <track-size> ...;
  grid-template-areas: "<grid-area-name> ..." "...";
  grid-gap: <grid-row-gap> <grid-column-gap>; /* 旧语法,请使用 gap */
  gap: <row-gap> <column-gap>; /* 现代标准 */
  justify-items: start | end | center | stretch;
  align-items: start | end | center | stretch;
  grid-auto-columns: <track-size>;
  grid-auto-rows: <track-size>;
  grid-auto-flow: row | column | row dense | column dense;
}

/* <track-size> 可以是:长度(px, %)、fr单位、minmax(min, max)、auto */
/* <grid-area-name> 是为网格区域定义的名称 */

子项属性

.grid-item {
  grid-column-start: <number> | <name> | span <number> | span <name> | auto;
  grid-column-end: <number> | <name> | span <number> | span <name> | auto;
  grid-row-start: <number> | <name> | span <number> | span <name> | auto;
  grid-row-end: <number> | <name> | span <number> | span <name> | auto;
  /* 简写属性 */
  grid-column: <start-line> / <end-line>;
  grid-row: <start-line> / <end-line>;
  grid-area: <row-start> / <column-start> / <row-end> / <column-end> | <area-name>;
  justify-self: start | end | center | stretch;
  align-self: start | end | center | stretch;
}

用法

基础用法

最基础的用法是定义一个固定列数和行数的网格,并将子项放置其中。

<!-- HTML结构:一个容器和若干子项 -->
<div class="container">
  <div class="item item-1">1</div>
  <div class="item item-2">2</div>
  <div class="item item-3">3</div>
  <div class="item item-4">4</div>
  <div class="item item-5">5</div>
  <div class="item item-6">6</div>
</div>
/* 在CSS文件中定义网格 */
.container {
  display: grid; /* 1. 声明为网格容器 */
  grid-template-columns: 100px 100px 100px; /* 2. 定义三列,每列100px宽 */
  grid-template-rows: 50px 50px; /* 3. 定义两行,每行50px高 */
  gap: 10px; /* 4. 设置行和列之间的间隙为10px */
  background-color: #f0f0f0;
  padding: 10px;
}

.item {
  background-color: #4CAF50;
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
}

这个例子创建了一个简单的3×2网格。子项会按照HTML中的顺序,从左到右、从上到下自动填充到每个网格单元格中。

进阶用法

1. 创建灵活的响应式布局

使用 fr 单位、minmax()repeat() 函数可以创建能自适应容器大小的布局。

.container {
  display: grid;
  /* 第一列最小200px,最大1份可用空间;第二列固定200px;第三列最小100px */
  grid-template-columns: minmax(200px, 1fr) 200px minmax(100px, 300px);
  /* 行高自动,但最小100px */
  grid-auto-rows: minmax(100px, auto);
  gap: 15px;
}

2. 使用命名区域进行直观布局

通过 grid-template-areas 可以像画草图一样定义布局,非常直观。

.container {
  display: grid;
  grid-template-columns: 1fr 3fr;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
  gap: 0; /* 此布局可能不需要间隙 */
  min-height: 100vh;
}

.item-header { grid-area: header; background: #8a2be2; }
.item-sidebar { grid-area: sidebar; background: #ff7f50; }
.item-main { grid-area: main; background: #6495ed; }
.item-footer { grid-area: footer; background: #3cb371; }
<div class="container">
  <div class="item item-header">Header</div>
  <div class="item item-sidebar">Sidebar</div>
  <div class="item item-main">Main Content</div>
  <div class="item item-footer">Footer</div>
</div>

3. 基于网格线的精准定位

可以精确控制一个子项占据哪几条网格线之间的区域。

.item-1 {
  /* 从第1条列线开始,跨越到第3条列线(即占据前两列) */
  /* 从第1条行线开始,跨越到第3条行线(即占据前两行) */
  grid-column: 1 / 3;
  grid-row: 1 / 3;
}

.item-2 {
  /* 从第2条列线开始,跨越2列 */
  /* 从第3条行线开始,到第4条行线结束 */
  grid-column: 2 / span 2;
  grid-row: 3 / 4;
}

易错点

1. 混淆 Grid 与 Flexbox 的适用场景

  • 错误理解:用Flexbox去做整体的页面二维布局,或者用Grid去处理简单的单行/列对齐。
  • 核心区别
    • Flexbox 是一维布局,专为单行或单列的内容分发和对齐设计。适合组件内部、导航栏、弹性列表等。
    • Grid 是二维布局,同时控制行和列。适合整个页面的宏观布局、卡片网格、仪表盘等。
  • 示例:一个产品卡片列表,如果只是水平排列并自动换行,用Flexbox。如果需要严格对齐到行和列的网格线上,用Grid。

2. 过度依赖网格线编号

  • 错误示例
    /* 当网格结构改变时,这些数字需要全部重新计算 */
    .item { grid-column: 3 / 5; }
    
  • 正确做法:尽可能使用命名网格线命名区域
    .container {
      grid-template-columns: [start] 1fr [content-start] 3fr [content-end] 1fr [end];
    }
    .item { grid-column: content-start / content-end; } /* 清晰且稳定 */
    

3. 忽略隐式网格的样式

当项目数量超过 grid-template-rows/columns 定义的范围时,浏览器会自动创建新的行/列(隐式网格)。如果未定义其尺寸,可能导致布局混乱。
错误示例

“`css
.container {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 只定义了3列 */
grid-template-rows: 100px 100px; /* 只定义了两行 */
}
/* 当有第7个项目时,它会跑到第三行,但行高是默认的`auto`,可能很矮 */
“`
– **正确做法**:使用 `grid-auto-rows` 和 `grid-auto-columns` 设置隐式网格的尺寸。
“`css
.container {
/* … 其他定义 … */
grid-auto-rows: 150px; /* 所有额外创建的行都高150px */
}
“`

最佳实践

使用命名线和区域提升可读性

如上文易错点2所示,为网格线和区域赋予有语义的名称,能极大提升CSS代码的可读性和可维护性。你的布局意图会直接从代码中体现出来,而不是隐藏在抽象的数字背后。

.page {
  display: grid;
  grid-template-columns:
    [full-start] minmax(1em, 1fr)
    [main-start] minmax(0, 70rem) [main-end]
    minmax(1em, 1fr) [full-end];
}

.content {
  /* 一目了然:内容从主区域开始到主区域结束 */
  grid-column: main-start / main-end;
}

在容器上定义布局,子项仅做微调

Grid的核心思想是“容器驱动布局”。应将绝大部分布局逻辑(定义轨道、区域)写在容器的CSS规则中。子项的属性(grid-column, grid-row)只应用于那些需要特殊定位或跨度的个别项目。这符合“关注点分离”原则,使布局更易于理解和整体修改。

利用 minmax()auto-fill/auto-fit 实现真正的响应式

对于需要自适应列数的布局(如相册、产品网格),避免编写多个媒体查询。使用 repeat() 配合 auto-fill/auto-fitminmax()

.container {
  display: grid;
  /* 在至少200px宽的前提下,尽可能多地填充列 */
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 1rem;
}
  • auto-fill:尽可能多地创建轨道,即使它们当前是空的(为未来元素留出空间)。
  • auto-fit:伸展当前已有的项目以填满可用空间。

使用 gap 而非 margin 控制间距

Grid布局中的 gap 属性是专门用来设置网格线之间间距的。相比于在子项上设置 margingap 有显著优势:
更简洁:只需在容器上设置一次。
更可控:间隙只出现在网格线之间,而不会在容器边缘产生多余间距。
无副作用:避免了 margin 折叠等经典CSS问题。