跳到主要内容

Grid 元素放置与区域

三种放置方式,先选对工具

方式写法适合
自动放置什么都不写,按 DOM 顺序填格卡片列表、相同结构的重复项
网格线放置grid-column / grid-row少量元素需要跨行跨列
命名区域grid-template-areasgrid-area页面级骨架,结构一目了然

按网格线放置元素

.item {
grid-column-start: 1;
grid-column-end: 3;
grid-row-start: 2;
grid-row-end: 4;
}

简写:

.item {
grid-column: 1 / 3; /* 从第 1 条竖线到第 3 条,占 2 列 */
grid-row: 2 / 4; /* 从第 2 条横线到第 4 条,占 2 行 */
}

🔢 结束线本身不属于该元素1 / 3 是「从 1 号线到 3 号线」,中间夹住了 2 个轨道,所以占 2 列而不是 3 列。差值就是跨度。

使用 span

不关心具体结束编号时,span 更好维护:

.item {
grid-column: span 2; /* 从自动位置开始,跨 2 列 */
grid-row: 2 / span 3; /* 从第 2 条横线开始,跨 3 行 */
grid-column: span 2 / -1; /* 右对齐到末尾,向左跨 2 列 */
}

实例:卡片列表中让第一个卡片变成“大卡片”:

.grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 16px;
}

.grid > :first-child {
grid-column: span 2;
grid-row: span 2;
}

使用负数网格线

.header {
grid-column: 1 / -1; /* 横跨整个显式网格 */
}

-1 表示显式网格的最后一条线。好处是列数变了也不用改代码。注意:负数编号只针对显式网格,不包括后来生成的隐式轨道。

命名网格线

.layout {
display: grid;
grid-template-columns:
[full-start] 1fr
[content-start] minmax(0, 960px)
[content-end] 1fr
[full-end];
}

.article {
grid-column: content-start / content-end;
}

/* 通栏背景图破出内容区,横跨满屏 */
.hero {
grid-column: full-start / full-end;
}

这是实现「内容居中限宽 960px,但部分元素可以满屏」的经典方案,比嵌套 wrapper 更干净。

💡 如果线名以 -start / -end 成对命名(如 content-start / content-end),就会自动形成一个名为 content 的区域,可以直接写 grid-column: content;

使用命名区域布局

这是可读性最好的写法——CSS 里直接画出了页面长什么样:

.layout {
display: grid;
grid-template-columns: 240px minmax(0, 1fr);
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
min-height: 100vh;
}

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

规则:

  • 每一行区域字符串的列数必须一致
  • 同名区域必须组成矩形,不能是 L 形或分离的两块。
  • . 表示空单元格(多个点也行,如 ...)。
  • grid-area 既可接收区域名,也可写作 row-start / column-start / row-end / column-end

带空格子的例子:

grid-template-areas:
"header header header"
"nav main . "
"footer footer footer";

响应式改写区域——只改一处,整个布局重排:

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

这里 main 被放到了 sidebar 前面,但 DOM 顺序没变。屏幕阅读器和键盘 Tab 仍然按 HTML 顺序走,因此要先保证 HTML 顺序符合阅读逻辑,再用 Grid 做视觉调整。

隐式网格与自动放置

当 Grid Item 数量超过显式轨道,或元素被放到显式网格之外,浏览器会自动创建隐式轨道。

.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: minmax(100px, auto); /* 隐式行至少 100px,内容多就长高 */
}
属性作用
grid-auto-rows设置隐式的尺寸
grid-auto-columns设置隐式的尺寸
grid-auto-flow控制自动放置的方向与策略
.container {
grid-auto-flow: row; /* 默认,优先按行填充,不够就新增行 */
grid-auto-flow: column; /* 优先按列填充,不够就新增列 */
grid-auto-flow: row dense; /* 尝试回填前面的空洞 */
}

dense 的效果与代价

.gallery {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-flow: row dense;
}

.gallery .wide { grid-column: span 2; }

没有 dense 时,宽卡片放不下就会换行,前一行留下空洞;加上 dense 后,后面的小卡片会被拿上来填进空洞。

⚠️ dense 会让视觉顺序与 DOM 顺序不一致,键盘焦点和屏幕阅读器仍遵循 DOM 顺序。只适合图库、瀑布流这类「顺序不重要」的内容,不要用在表单、列表导航上。

一个完整的后台页面骨架示例

<div class="admin">
<header class="admin-header">顶栏</header>
<nav class="admin-nav">侧边栏</nav>
<main class="admin-main">主内容</main>
<aside class="admin-aside">右侧面板</aside>
<footer class="admin-footer">底栏</footer>
</div>
.admin {
display: grid;
grid-template-columns: 220px minmax(0, 1fr) 280px;
grid-template-rows: 56px minmax(0, 1fr) 48px;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
min-height: 100vh;
}

.admin-header { grid-area: header; }
.admin-nav { grid-area: nav; overflow-y: auto; }
.admin-main { grid-area: main; overflow-y: auto; min-width: 0; }
.admin-aside { grid-area: aside; }
.admin-footer { grid-area: footer; }

@media (max-width: 1024px) {
.admin {
grid-template-columns: 220px minmax(0, 1fr);
grid-template-areas:
"header header"
"nav main"
"footer footer";
}
.admin-aside { display: none; }
}

两个关键细节:minmax(0, 1fr) 防止主内容被长内容撑破;行上的 minmax(0, 1fr) 配合子元素 overflow-y: auto,才能实现「顶栏底栏固定、中间独立滚动」。