深入了解 Grid 布局的响应式用法

1,608 阅读6分钟

关于 Grid 布局的详细属性介绍和使用方式,这篇阮一峰的 《CSS Grid 网格布局教程》 中有详尽的介绍,不再赘述,建议详细阅读。本文摘取了其中与响应式布局有关的内容,并结合业务实际,梳理列划分的技巧和坑点,帮助大家深入认识 grid 布局。

涉及到的高频 CSS 属性值可以说相对冷门但又极为常用。冷门是因为这些属性相比之下受众并不广泛,常用则是因为「响应式栅格布局」非常依赖这些属性。

grid-template-columns

定义了容器之后,需要划分行和列。一般来说,行的划分(row)不需要关心,自然向下堆砌即可;而列(column)的划分受到容器宽度限制,它决定了一行能容纳多少个项目,也间接决定了总行数,是影响布局的关键因素

常见的列划分形式如下:

.container {
  display: grid;
  grid-template-columns: 33.33% 33.33% 33.33%; // 百分比宽度
  grid-template-columns: 100px 100px 100px;    // 固定宽度
  grid-template-columns: auto 50px auto;       // 自动宽度(auto)
  grid-template-columns: 150px 1fr 2fr;        // 比例宽度(fr)
}

其中涉及百分比宽度、固定宽度、自动宽度(auto)、比例宽度(fr)。

auto 自动宽度

auto关键字表示由浏览器自己决定长度,常见用法如下:

grid-template-columns: 100px auto 100px; // 第二列的宽度 = 总宽度 - 100px - 100px
grid-template-columns: 100px auto auto;  // 多个 auto 将会平分剩余空间

多个 auto 关键字将会「平分」剩余空间,如果我们想要按比例划分剩余空间呢?好办,用fr关键字。

fr 比例宽度

为了方便表示比例关系,grid 布局提供了fr关键字(fraction 的缩写,意为"片段")。

如果两列的宽度分别为1fr和2fr,就表示后者是前者的两倍。下面代码表示两个宽度相等的列

grid-template-columns: 1fr 1fr;
grid-template-columns: 2fr 2fr;
grid-template-columns: 3fr 3fr;
...

聪明的你一定发现了,在等比例划分的情况下,frauto的行为是一致的,上面的布局还可以这样:

grid-template-columns: auto auto;

fr也可以与固定宽度结合使用,这时会非常方便。下面代码表示,第一列的宽度为 150px,第二列和第三列按照 1:2 分配剩余空间。

grid-template-columns: 150px 1fr 2fr;

好奇的你一定想问,auto 是否可以和 1fr 混用达到平分的目的呢?答案是,不可以。

grid-template-columns: auto 1fr 1fr auto; // 会变成什么样子?

如下,auto列将会被尽可能挤压直到最小宽度,而 fr 行为不受影响,依旧是按比例分割剩余空间。

image

通常不会这样使用,除非你真的有这样的需要。

repeat

重复写同样的值非常麻烦,尤其网格很多时。这时,可以使用repeat()函数,简化重复的值。

使用方式:repeat(重复的次数, 重复的值)。

重复的次数可以是

grid-template-columns: repeat(3, 100px);         // 固定次数重复
grid-template-columns: repeat(auto-fill, 100px); // 根据宽度自动计算重复次数

重复的可以是

grid-template-columns: repeat(3, 33.3%);              // 百分比重复
grid-template-columns: repeat(3, 100px);              // 固定值重复
grid-template-columns: repeat(3, 1fr);                // 比例重复
grid-template-columns: repeat(3, 50px 1fr 2fr);       // 模式重复
grid-template-columns: repeat(3, minmax(100px, 1fr)); // 响应式重复

repeat()通常配合 minmax()、auto-fill等属性使用,可以实现各种灵活的响应式布局。

响应式布局

auto-fill

有时,单元格的宽度是固定的,但是容器的宽度不确定,会随着窗口宽度的变化而变化。

如果希望每一行容纳尽可能多的单元格,这时可以使用auto-fill关键字表示自动填充。

grid-template-columns: repeat(auto-fill, 100px);

image

但我们可以明显看到,在剩余空间不足一个单元格宽度时,会出现空隙并不美观。为了解决这个问题,我们可以加入minmax函数,使单元格宽度在一定范围内浮动。

minmax

产生一个长度范围,表示长度就在这个范围之中。

使用方式:minmax(最小值,最大值)

下面代码中,minmax(150px, 1fr)表示列宽不小于150px,不大于1fr。

换句话说,当宽度小于 100px 时,该值实际为 150px,当宽度大于 1fr 时,该值为 1fr

grid-template-columns: 1fr 1fr minmax(150px, 1fr);

image

可以看到,第三列的宽度大于 150px 时宽度为 1fr,并随之变化;当宽度小于150px 时,固定为 150px。

🎉 auto-fill & minmax

没错,聪明的你一定想到了。既然 auto-fill 配合 repeat 可以尽可能填充单元格列,minmax 又能提供一个浮动范围。那我们只需要将二者结合起来,

grid-template-columns: repeat(auto-fill, minmax(100px, auto));
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));  // 等价

就能打造出下面这样的响应式效果,而这也是我们业务中最常用的栅格布局样式👇🏻:

image

按照上面的公式模板,我们只需要为单元格设置一个基准宽度即可(如:100px),其他由浏览器负责计算。

QA

为什么会出现横向滚动条?

根据最新标准,grid-column-gapgrid-row-gapgrid-gapgrid- 前缀已经删除。

在实践中,我们通常会配合其他属性,如 gap 属性,一同使用,划分单元格之间的间距。

下面的代码设置了 gap: 20px; 表示一行有 3 列,3 列均分占满 1 行,在此基础上还要留出 2 * 20px 的空隙,作为单元格之间的间隔。

.container {
  display: grid;
  overflow: auto;
  grid-template-columns: repeat(3, 33.33%);
  gap: 20px;
}

很明显,这样的布局一定会出现滚动条,且间距(gap)越大,滚动条越明显。因为三列已经占满了一行,没有多余的空间分配给 gap 了。如下所示,可以看到明显的滚动条:

image.png

如果想在实现 3 列均分且占满效果的同时,还想拥有间隙,可以这样:

gap: 20px;
grid-template-columns: repeat(3, auto);
grid-template-columns: repeat(3, 1fr);  // 或

当然,如果你愿意,根据需要使用 minmax 也是可以的,而我们上方提到的响应式布局,更是天然支持这样布局。


看到这里的你很有前途,不如点个赞吧~