Skip to main content

深入理解 Grid 布局

Grid 网格布局将页面划分成一个个网格,可以任意组合不同的网格,做出各种布局。与 Flex 的区别在于,Flex 布局是轴线布局,只能指定项目针对轴线的位置,可看作一维布局。而 Grid 布局则是将容器划分成行和列,产生单元格,然后指定项目所在的单元格,可看作二维布局,比 Flex 布局强大。

一、容器包裹层属性

1、grid-template-[columns/rows]

  • grid-template-columns:设置每一列的列宽;
  • grid-template-rows:设置每一行的行高。
HTML
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<!-- ... -->
<div class="item">9</div>
</div>
CSS
.container {
display: grid;
grid-template-columns: 100px 100px 100px;
grid-template-rows: 100px 100px 100px;
}

效果如下:

1-1、百分比

上面可写成固定包裹层大小,单项使用百分比的形式,效果一样:

.container {
width: 300px;
height: 300px;
display: grid;
grid-template-columns: 33.33% 33.33% 33.33%;
grid-template-rows: 33.33% 33.33% 33.33%;
}

1-2、repeat()

可使用 repeat() 函数,简化重复的值。上面百分比可简写为:

.container {
width: 300px;
height: 300px;
display: grid;
grid-template-columns: repeat(3, 33.33%);
grid-template-rows: repeat(3, 33.33%);
}

repeat() 除了重复值,还可以重复某种模式:

.container {
height: 300px;
display: grid;
grid-template-columns: repeat(2, 40px 50px 60px);
grid-template-rows: repeat(3, 33.33%);
}

效果如下:

1-3、auto-fill

auto-fill 关键字表示自动填充,在行(或列)上容纳尽可能多的固定单元格。举个例子:

.container {
width: 300px;
height: 300px;
display: grid;
grid-template-columns: repeat(auto-fill, 70px);
grid-template-rows: repeat(auto-fill, 120px);
}

上面代码表示在宽高 300px 的容器中,每列按 70px 宽度的单元格自动填充,直到容器不能放置更多的列,按 120px 高度的单元格自动填充,直到容器不能放置更多的行,如果填充后的高度不够,会压缩最后一列/行,效果如下:

1-4、fr

网格布局提供了 fr 关键字(fraction 的缩写,意为"片段")表示倍数,如果两列的宽度分别为 1fr 和 2fr,就表示后者是前者的两倍。举个例子:

.container {
width: 300px;
height: 300px;
display: grid;
grid-template-columns: 1fr 2fr;
grid-template-rows: 1fr 1fr 1fr;
}

列指定了 2 列以 1:2 的比例自适应,行只指定了 3 个单元格的比例,剩下两个单元格会以最小高度显示,效果如下:

fr 也可以与具体尺寸一起使用:

.container {
width: 300px;
height: 300px;
display: grid;
grid-template-columns: 100px 1fr 2fr;
grid-template-rows: 1fr 1fr 1fr;
}

列指定了第一列固定 100px,剩下两列以 1:2 的比例自适应,行指定了 3 个单元格平均分,效果如下:

1-5、minmax()

minmax() 传入最小值和最大值,指定单元格尺寸范围。举个例子:

.container {
width: 300px;
height: 300px;
display: grid;
grid-template-columns: 1fr 1fr minmax(30px, 0.5fr);
grid-template-rows: 1fr 1fr 1fr;
}

列指定了第三列的宽度在 30px 到 0.5fr 之间,效果如下:

1-6、auto

auto 关键字表示由浏览器自己决定长度。举个例子:

.container {
width: 300px;
height: 300px;
display: grid;
grid-template-columns: 1fr 1fr auto;
grid-template-rows: 1fr 1fr auto;
}

这里第 3 列与第 3 行指定 auto,使对应单元格以最小宽度/高度显示,效果如下:

1-7、网格线命名

可在 grid-template-[columns/rows] 中用方括号给对应位置的网格线命名,方便单项位置的存放:

.container {
display: grid;
grid-template-columns: [c1] 100px [c2] 100px [c3] auto [c4];
grid-template-rows: [r1] 100px [r2] 100px [r3] auto [r4];
}

2、grid-template-areas

grid-template-areas 用于定义区域,一个区域由单个或多个单元格组成,一般结合子项的 grid-area 使用。可选值如下:

  • <grid-area-name>ㅤ指定网格区域 grid-area 的名称;
  • .ㅤ表示一个空的网格单元;
  • noneㅤ表示没有定义网格区域。

举个例子:

HTML
<div class="container">
<div class="item-a">1</div>
<div class="item-a">2</div>
<div class="item-b">3</div>
<div class="item-c">4</div>
<div class="item-d">5</div>
</div>
CSS
.container {
width: 300px;
height: 300px;
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: auto;
grid-template-areas:
"a a a a"
"b b . c"
"d d d d";
}

.item-a {
grid-area: a;
}

.item-b {
grid-area: b;
}

.item-c {
grid-area: c;
}

.item-d {
grid-area: d;
}

效果如下:

3、[column/row]-gap | gap

  • column-gap:设置列间距;
  • row-gap:设置行间距;
  • gap:列间距与行间距的简写。

举个例子:

.container {
width: 300px;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: repeat(3, calc((300px - 20px) / 3));
/* 写法一 */
column-gap: 10px;
row-gap: 10px;
/* 写法二 */
gap: 10px 10px;
/* 写法三 */
gap: 10px;
}

效果如下:

4、grid-auto-flow

grid-auto-flow 决定子元素的排列方式,默认为 row。

4-1、row | column

  • row:按"先行后列"的顺序排列;
  • column:按"先列后行"的顺序排。

举个例子,默认 row 的排列如下:

设为 column:

.container {
/* ... */
grid-auto-flow: column;
}

效果如下:

4-2、[row/column] dense

  • row dense:按"先行后列"的顺序排列,并尽可能紧密填满;
  • column:按"先列后行"的顺序排,并尽可能紧密填满。

举个例子:

HTML
<div class="container">
<div class="item item1">1</div>
<div class="item item2">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
</div>
CSS
.container {
width: 300px;
height: 300px;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: auto;
}

.item1 {
grid-column-start: 1;
grid-column-end: 3;
}

.item2 {
grid-column-start: 1;
grid-column-end: 3;
}

没设 row dense 之前,效果如下:

设为 row dense:

.container {
/* ... */
grid-auto-flow: row dense;
}

效果如下:

column dense 同理。

4、justify-[content/items]

  • justify-content:设置整个内容区域在包裹层中的水平位置;
  • justify-items:设置单元格内容的水平位置。

5、align-[content/items]

  • align-content:设置整个内容区域的垂直位置;
  • align-items:设置单元格内容的垂直位置;

二、单项属性

1、grid-[column/row]-[start/end]

  • grid-column-start:设置单项左边框所在的垂直网格线;
  • grid-column-end:设置单项右边框所在的垂直网格线;
  • grid-row-start:设置单项上边框所在的水平网格线;
  • grid-row-end:设置单项下边框所在的水平网格线。

举个例子:

HTML
<div class="container">
<div class="item item1">1</div>
<div class="item item2">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
</div>
CSS
.container {
width: 300px;
height: 300px;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
}

.item1 {
grid-column-start: 2;
grid-column-end: 4;
}

.item2 {
grid-row-start: 2;
grid-row-end: 4;
}

效果如下:

这里除了使用纯数字指定是第几根网格线外,还可以使用 grid-template-[columns/rows]命名的网格线,也可以使用 span 关键字,表示水平跨越了多少个单元格,上面 .item1 的写法等同于:

.item1 {
grid-column-start: 2;
grid-column-end: span 2;
}

注意 span 后面要加空格。

2、grid-[column/row]

  • grid-columngrid-column-startgrid-column-end 的合并简写;
  • grid-rowgrid-row-startgrid-row-end 的合并简写;

上面的写法等同于:

.item1 {
grid-column: 2 / 4;
/* 或 */
grid-column: 2 / span 2;
}

.item2 {
grid-row: 2 / 4;
}

3、grid-area

grid-area 指定单项放在哪个区域,有两种用法:

  1. 配合上面 grid-template-areas 使用区域名称;
  2. 指定垂直/水平网格线的起始/终止位置,控制单项存放的区域,格式为:
grid-area: <row-start> / <column-start> / <row-end> / <column-end>;

上面 grid-template-areas 的例子可用下面 grid-area 控制网格线的写法:

HTML
<div class="container">
<div class="item-1">1</div>
<div class="item-2">2</div>
<div class="item-3">3</div>
<div class="item-4">4</div>
<div class="item-5">5</div>
</div>
CSS
.container {
width: 300px;
height: 300px;
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
}

.item1 {
grid-area: 1 / 1 / 2 / span 4;
}

.item2 {
grid-area: 1 / 1 / 2 / span 4;
}

.item3 {
grid-area: 2 / 1 / 3 / span 2;
}

.item4 {
grid-area: 2 / 4 / 3 / span 1;
}

.item5 {
grid-area: 3 / 1 / 4 / 5;
}

效果如下:

4、[justify / align / place]-self

  • justify-self:设置单项单元格内容的水平位置;
  • align-self:设置单项单元格内容的垂直位置;
  • place-selfalign-selfjustify-self 的合并简写。

三、Grid 布局的兼容性

四、总结