grid-template-columns

Avatar of Mojtaba Seyedi
Mojtaba Seyedi

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 $200 免费积分!

grid-template-columns CSS 属性是 CSS 网格布局规范 的一部分,通过指定网格轨道的大小及其行名来定义 网格容器 的列。

.sidebar-layout {
  display: grid;
  grid-template-columns: 300px 1fr;
}

值得注意的是,当我们深入研究 grid-template-columns 属性时,网格线和网格轨道之间的区别。网格线是指定义网格列和行的线条的名称。网格轨道是指网格线之间的空间长度。

In this example of a CSS grid layout, the grid lines are exposed and numbered along the bottom (the vertical grid column lines) and the right (the horizontal grid row lines). The track sizes are labeled along the top and left edges.

语法

grid-template-columns: none | <track-list> | <auto-track-list> | subgrid <line-name-list>?

完整定义

where:
<track-list> = [ <line-names>? [ <track-size> | <track-repeat> ] ]+ <line-names>?
<auto-track-list> = [ <line-names>? [ <fixed-size> | <fixed-repeat> ] ]* <line-names>? <auto-repeat>
[ <line-names>? [ <fixed-size> | <fixed-repeat> ] ]* <line-names>?
<line-name-list> = [ <line-names> | <name-repeat> ]+

where:
<line-names> = '[' <custom-ident>* ']'
<track-size> = <track-breadth> | minmax( <inflexible-breadth> , <track-breadth> ) | fit-content( [ <length> | <percentage> ] )
<track-repeat> = repeat( [ <integer [1,∞]> ] , [ <line-names>? <track-size> ]+ <line-names>? )
<fixed-size> = <fixed-breadth> | minmax( <fixed-breadth> , <track-breadth> ) | minmax( <inflexible-breadth> , <fixed-breadth> )
<fixed-repeat> = repeat( [ <integer [1,∞]> ] , [ <line-names>? <fixed-size> ]+ <line-names>? )
<auto-repeat> = repeat( [ auto-fill | auto-fit ] , [ <line-names>? <fixed-size> ]+ <line-names>? )

where:
<track-breadth> = <length-percentage> | <flex> | min-content | max-content | auto
<inflexible-breadth> = <length> | <percentage> | min-content | max-content | auto
<fixed-breadth> = <length-percentage>
  • 初始值: none
  • 应用于: 网格容器
  • 继承:
  • 计算值: 如指定,但将相对长度转换为绝对长度
  • 动画类型: 简单的长度、百分比或 calc 列表,前提是列表中只有长度、百分比或 calc 组件的值不同。

/* Keyword value */
grid-template-columns: none;

/* <track-list> values */
grid-template-columns: 200px 1fr 180px;
grid-template-columns: [linename col1] 250px [line2];
grid-template-columns: [sidebar] 1fr [content] 2fr;
grid-template-columns: fit-content(50%);
grid-template-columns: minmax(200px, 1fr) minmax(100px, 1fr);
grid-template-columns: repeat(4, 1fr);
grid-template-columns: subgrid;
grid-template-columns: masonry;

/* <auto-track-list> values */
grid-template-columns: 100px repeat(auto-fill, 100px) 200px;
grid-template-columns: 100px repeat(2, 1fr auto) 200px repeat(3, 5fr);
grid-template-columns: minmax(150px, max-content) repeat(auto-fill, 180px) 15%;
grid-template-columns: [col1] 100px [col1-end] repeat(auto-fit, [line3] 400px);

/* Global values */
grid-template-columns: inherit;
grid-template-columns: initial; /* same as `none` */
grid-template-columns: revert;
grid-template-columns: unset;

none

这是默认值。使用 none 值意味着 grid-template-columns 不生成任何显式网格轨道,这意味着列是隐式生成的(即在您无需显式定义它们的情况下为您生成),并且轨道大小由 grid-auto-columns 属性定义。

请注意,grid-template-columns 不是创建显式网格列轨道的唯一方法。它也可以使用 grid-template-areas 属性完成,该属性允许使用自定义名称(例如 sidebarmain 等)定义网格区域。

隐式网格和显式网格之间的区别在 Manuel Matuzovic 的这篇文章 中得到了很好的总结。

<length>

此值可以是任何有效的非负 CSS 长度,例如 pxemrem 等,用于指定列的轨道大小(即宽度)。

<percentage>

这是一个相对于网格容器的内部内联大小的非负值。如果网格容器的大小取决于其轨道的尺寸,则百分比必须与声明 auto 相同。

使用百分比值的一个缺点是,如果您在轨道之间添加 间隙,则间隙的大小将添加到轨道的尺寸中,这 可能会导致溢出。使用 fr 单位auto 关键字来调整轨道大小并防止这种情况发生。

<flex>

这是一个以 fr 单位 表示的非负值,它允许您通过将轨道的大小指定为网格容器中可用空间的一部分来创建灵活的网格轨道。这样,当网格改变宽度时,列也会随之改变,从而形成更具响应性的网格。

例如,考虑一个三列网格容器,宽度为 900px。假设第一列(左侧)的宽度是固定的(即它不会改变),为 300px,而第二列占据一个分数单位(1fr),第三列占据两个分数单位(2fr)。

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

后两列是分数的,所以它们将占据任何剩余的可用空间。在这种情况下,可用空间是在第一列的固定宽度 300px 被考虑后剩下的空间。然后,后两列根据它们获得的分数来分配剩下的空间。

在这个例子中,剩余的可用空间是 600px(即 900px 减去 300px)。第二列获得这个空间的一个分数(1fr),而第三列获得两个分数(2fr)。让我们来算一下 600px 的一个分数的宽度。

1fr = ([Grid Container Width] - [Fixed Column Width]) / [Sum of the flex factors]
1fr = (900px - 300px) / 3
1fr = 600px / 3
1fr = 200px

啊哈!一个分数是 200px。由于第二列是 1fr,它也必须是 200px。这样就留下了 400px 的可用空间(900px300px200px),这恰好是第二列大小的两倍。

但是等等!还有更多。

记住,当网格计算有多少可用空间来分配给分数列时,它会将网格轨道之间添加的任何间隙考虑在内。当然,这里的好处是我们的列永远不会超出网格容器。

让我们在之前的例子中添加一个间隙。

.grid {
  display: grid;
  width: 900px;
  grid-template-columns: 300px 1fr 2fr;
  gap: 15px;
}

我知道我们在这里已经声明了间隙,但实际上我们声明了两个间隙。这是因为每列之间都有一个 15px 的间隙(第一列和第二列之间有一个,第二列和第三列之间也有一个)。这意味着我们网格中有 30px 的间隙需要考虑在可用空间内。

1fr = ([Grid Container Width] - [Gaps] - [Fixed Column Width]) / [Sum of the flex factors]
1fr = (900px - 30px - 300px) / 3
1fr = 570px / 3
1fr = 190px

我不知道你怎么样,但我不喜欢做太多手工计算。这就是 CSS 网格如此棒的原因 - 它能处理所有这些!

minmax(min, max)

minmax() 函数接受两个参数:最小长度值和最大长度值。它告诉网格容器,grid-template-columns 的宽度不能小于最小值,但也不能大于最大值。 我们关于 CSS 函数的指南对该函数的工作原理进行了更全面、详细的解释

以下是一个例子。

grid-template-columns: 200px minmax(100px, 400px);

这里有两列:一列宽度为 200px,另一列表示为 minmax(100px, 400px)。看起来很奇怪,对吧?但这只是说,第二列必须占用至少 100px 的空间,但在第一列占用 200px 后不能超过 400px

更清楚地说:只要有超过 100px 的可用空间,第二列就可以扩展到 400px,但必须在那里停止。否则,列的宽度为 100px

minmax 参数接受所有以下值,但 min 值不能是 flex 值(例如 1fr

<length-percentage> | <flex> | min-content | max-content | auto

所以,这无效,因为 min 值是 flex 值。

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

但这些都是有效的。

grid-template-columns: minmax(auto, 1fr) 3fr;
grid-template-columns: minmax(200%, 1fr) 1fr;

auto

在大多数情况下,auto 关键字的行为类似于 minmax(min-content, max-content)

由于 auto 轨道大小可以通过 align-contentjustify-content 属性来拉伸,因此它们默认情况下会占据网格容器中的任何剩余空间(你知道的,auto-matically)。也就是说,auto 轨道大小在分配剩余空间时无法战胜 fr 单位 - 它们会调整到其内容的最大尺寸。

看一下这两个轨道示例的结果。

grid-template-columns: auto auto auto;
grid-template-columns: auto 1fr auto;

当所有三列都设置为 auto(我们也可以写成 repeat(3, auto) - 但稍后会详细介绍),它们只会共享相等的空间。但是,当我们在中间插入一个分数单位作为第二列时,auto 列的宽度仅与其内部内容一样宽,而 1fr 列占据剩余的空间。

Two rows each containing three white boxes against an orange background. The top row boxes are evenly spaced with the auto keyword in them. The second row shows the two outer boxes squished toward the edges against the middle box that is labelled with 1 fractional unit, showing how those units affect the grid-template-columns property..
演示 fr 单位与 auto 轨道的行为。

min-content

min-content 关键字表示元素在不溢出内容的情况下,在网格容器中可以占据的最小空间量。内容可以是文本、图像或视频。

假设内容是“CSS is awesome.”,min-content 是“awesome”这个词的宽度,因为它是内容中最宽的部分(比“CSS is”宽)。如果列再窄一些,那么文本就会开始溢出容器。

在代码中,它看起来像这样。

.grid {
  display: grid;
  grid-template-columns: min-content 1fr;
  gap: 1rem;
}

…这将导致类似于以下内容的结果。

One row containing two boxes. The first box says CSS is Awesome and is as wide as the word awesome. The rest of the row is taken up by the box on the right that is sized with one fractional unit.
演示 min-content 关键字在网格布局中的行为。

max-content

max-content 关键字表示元素所需的最小尺寸,以便所有内容都能容纳,而不会被换行或溢出。我知道,一个包含“max”的名字让人感觉好像我们正在处理最大尺寸,所以这个值可能有点令人费解。

如果我们重新审视上面的 min-content 示例,一个尺寸值为 max-content 的网格轨道将增长,直到其内容可以容纳在一行中。因此,在“CSS is awesome”的情况下,max-content 是这三个词在一行中占据的空间大小。

.grid {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 1rem;
}
A row containing two white boxes against an orange background. The box on the left says CSS is Awesome all on a single line and the box is as wide as the content. The box on the right fills up the remaining space in the row and is labelled with one fractional unit.
演示网格布局中max-content关键字的行为

fit-content( <length-percentage> )

fit-content() 函数(在我们的 CSS 函数指南中有一个详细解释)利用可用的空间,并接受percentagelength值作为网格轨道允许的最大尺寸,同时确保轨道永远不会超过max-content,也不会收缩到最小值以下。最小值通常(但并非总是)等于min-content

.grid {
  display: grid;
  grid-template-columns: fit-content(700px) fit-content(700px) 1fr;
  gap: 1rem;
}

在下图中,第一列不会超过其max-content大小(即“fit-content(700px)”这几个词在一行上的宽度)——它只伸展到足以容纳其内容。然而,第二列有更多内容,并且在达到700px宽度后停止伸展,这是设置给函数的限制

Three white boxes in a single row against an orange background. The first box is labeled fit-content(700px). The second box is labelled fit-content(700px) but with more content so it expands until it hits the 700px limit. The third box is labeled with one fractional unit.
因此,对于前两列,我们说它们应该与最大内容一样宽,但最多不超过700px。如果它可以在该限制内容纳所有内容,那就太好了,在达到max-content的地方停止。否则,尽可能地显示内容,直到达到700px,然后开始换行。

[linename]

虽然网格线始终可以通过隐式数字名称来引用,但我们也可以为它们指定自定义名称,以便在更复杂的网格中使代码更易于理解。然后,在通过行名定位网格项目时,可以引用每个行名。

网格线可以通过在方括号内添加名称并将每个名称用空格隔开,来拥有多个名称

grid-template-columns: [first content-start] 1fr [content-end sidebar-start] 300px [lastline];
Two white boxes in a single row against an orange background. The left box is labeled with one fractional unit. The right box is labeled with 300px. Black dashed lines indicate where the line tracks are and they are labeled with custom names, content-start, content-end, lastline.
演示网格布局的行名和数字索引。前两行有多个名称。

请注意,行名是<custom-ident>,这是一种通用的数据类型,代表任何有效的 CSS 标识符,不会被误解为该属性值定义中的预定义关键字。因此,我们可以将行命名为super-awesome-spider-monkey,但不能使用会导致冲突的全局 CSS 值,例如spanautoinheritinitial等等。

此外,这些标识符是完全区分大小写的。例如,CSS 将sidebar-endSidebar-Name视为两个完全不同的、无关的行名。此外,行名可以通过grid-template-columns属性显式分配,也可以通过使用grid-template-areas属性的命名网格区域隐式分配。

repeat([ <positive-integer> | auto-fill | auto-fit ] , <track-list>)

repeat() 函数是定义grid-template-columns数量的有效方法,当列相同时。该函数接受列数,然后是列大小

/* Writing this */
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;

/* is the same as this: */
grid-template-columns: repeat(5, 1fr);

另一个例子,这次来自规范

grid-template-columns: 10px [col-start] 250px [col-end]
                       10px [col-start] 250px [col-end]
                       10px [col-start] 250px [col-end]
                       10px [col-start] 250px [col-end] 10px;

/* same Ss above, except easier to write */
grid-template-columns: repeat(4, 10px [col-start] 250px [col-end]) 10px;

auto-fillauto-fit

除了显示重复次数的整数外,auto-fillauto-fit这两个关键字也被允许作为repeat()函数的第一个参数。

与固定数量的重复次数不同,这些关键字允许你显示尽可能多的特定大小的列,这些列可以容纳在网格容器的行中。

auto-fillauto-fit这两个关键字非常相似。两者都尝试将尽可能多的网格项目自动放入网格列中,然后再换行。区别在哪?auto-fill填充尽可能多的列,并在它用完项目后,它会将剩余的空间留空。另一方面,auto-fit会增加列的宽度,这样就不会剩下任何空隙。

Two rows office white boxes against an orange background. Both have an example of grid-template-columns, but one uses the auto-fill keyword and the other uses auto-fit.
演示auto-fill如何创建空列,而auto-fit如何拉伸现有列。

使用repeat()函数时,有一些限制值得注意

  • 它无法在repeat()函数中嵌套repeat()函数。
/* This is invalid */
grid-template-columns: repeat(4, 1fr repeat(5, 1fr));
  • 在使用auto-fillauto-fit时,它不接受内在或灵活长度值(例如fr单位)。它只接受显式轨道大小,这样它才能计算进入网格容器的列数。
/* This is invalid */
grid-template-columns: repeat(auto-fit, 1fr);
  • 但是,只要第一个值是正数,就可以将内在或灵活尺寸用作函数的第二个值。
/* These are invalid */
grid-template-columns: repeat(auto-fit, 1fr);
grid-template-columns: repeat(min-content, 1fr);

/* This is valid */
grid-template-columns: repeat(6, 1fr);
  • 在使用auto-fillauto-fit时,它只能在grid-template-columns轨道列表中使用一次。但是,只要第二个值是固定的,我们就可以使用多个repeat()函数。
/* These are invalid */
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)) 100px repeat(auto-fill, minmax(5rem, auto));
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)) 100px repeat(3, 1fr);

/* This is valid */
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)) 100px repeat(3, 200px);

subgrid

Subgrid 被认为是实验性的,在撰写本文时,它只在 Firefox 中受支持。

我们可以在网格创建网格吗?当然可以!这要归功于subgrid关键字值。声明它允许内部(子)网格共享外部(父)网格的轨道线,从而实现更一致的轨道线,而无需重新声明所有轨道线。

因此,假设我们在网格中有一个网格

.grid-container {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}
.grid-container .grid-item {
  display: grid;  
}

我们可以将嵌套网格转换为subgrid,以与父网格共享轨道线

.grid-container {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1rem;
}
.grid-container .grid-item {
  display: grid;  
  grid-template-columns: subgrid;
}

现在,子网格的项目将根据主网格容器的轨道大小进行放置和调整大小。例如,考虑以下 HTML

<div class="grid">
  <div class="item"></div>

  <div class="item subgrid">
    <div class="subitem"></div>
    <div class="subitem"></div>
  </div>

  <div class="item"></div>
  <div class="item"></div>
</div>

现在让我们创建一个子网格

 .grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr); /* Establish a grid with 4 tracks */
}
.item {  
  grid-column: 1/-1; /* Make all items as wide as the 4 tracks */
}
.subgrid {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: 3/-1; /* Make the subgrid item size, half of the other items */
}

在这里,你可以看到子网格项目根据父网格的轨道大小进行调整

A four-by-four grid of white boxes. The second row contains two subgrid items that are flush to the third and four tracks of the parent grid. All of the track lines are labeled and show how the subgrid items use the parent tracks but still start with a track line of one.
子网格布局

子网格中的间隙是由父网格继承的,但可以通过子网格元素上的不同gap值来覆盖

.grid-container {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1rem; /* This is inherited by the child grid */
}
.grid-container .grid-item {
  display: grid;  
  grid-template-columns: subgrid;
  gap: 0.5rem; /* This overrides the parent grid's gap */
}

子网格有自己的行号。例如,当您在子网格中使用行号1时,它指向子网格的第一行,而不是父网格。因此,即使子网格从父网格的第三条轨道线上开始,子网格的第一条轨道线仍然是1,而不是3

当然,我们可以在子网格中声明自定义网格线名称。

.grid-container .grid-item {
  display: grid;  
  grid-template-columns: subgrid [sidebar-start] [sidebar-end] [main-start] [main-last];
}

哦,我们也可以在这里完全使用repeat()函数来指定轨道线名称。

.grid-container .grid-item {
  display: grid;  
  grid-template-columns: subgrid repeat(2, [a] 1fr [b]);
}

不过,需要注意的是,repeat()函数会合并任何彼此相邻的轨道线名称。

/* These are equivalent */
grid-template-columns: repeat(2, [a] 1fr [b]);
grid-template-columns: [a] 1fr [b a] 1fr [b];

请注意,在子网格中,您不能在该维度上拥有任何隐式轨道。因此,如果您添加更多网格项,它们将被放置在子网格的现有显式轨道中。您可以在下图中看到在之前示例的子网格中添加一个子项的结果。

The same subgrid illustration but showing three grid items on two rows that are squished together with no vertical spacing.
子网格不会生成隐式轨道。

masonry

您知道我们所说的masonry是什么吗?它是一种很酷的布局,其中网格中的项目根据列中可用的垂直空间进行平铺和拼凑。它在几年前由David DeSandro 的同名 JavaScript 库普及。

An illustration of a five-column masonry layout of photos with thick rounded white borders against an orange background.
砖石布局

由于 CSS 网格,砖石布局将成为我们可以不用求助于 JavaScript 就可以完成的事情。但是,在撰写本文时,它仍然是CSS 网格规范第 3 级的一部分,目前仍处于编辑草案阶段。然而,它在 Firefox 中可以通过一个标志使用。

Screenshot of the Firefox about:config settings with a search for masonry and the option to enable the masonry flag.

我们可能会在规范真正发布之前看到规范的更改。但以下是它目前的样子

.container {
  display: grid;
  grid-template-columns: masonry;
  grid-template-rows: repeat(4, 1fr);
}

示例

耶,演示时间!我有一些示例展示了您在使用 CSS 网格布局时可能会遇到的grid-template-columns属性的功能。

可以使用以下 CSS 实现一个简单的侧边栏布局

.layout {
  display: grid;
  grid-template-columns: 1fr 250px;
}

以下是结果

响应式且灵活的卡片布局,具有动态数量的项目

这可能是其中最神奇的代码片段。假设您想在它换行之前将尽可能多的列打包到网格行中。使用此代码片段,我们将repeat()auto-fitminmax()的功能结合起来,以实现这一点。

grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));

通过这种方式,我们获得了重复数量的列(感谢repeat()),这些列将填充网格的所有可用空间(感谢auto-fit),同时永远不会缩小到小于250px,并且每个都占用相等的空间分数(感谢minmax())。

对齐表单元素

您是否曾经发现自己一直在与 CSS 较劲,试图让表单控件对齐?经典的案例是带有堆叠文本输入的表单,其中输入标签在左侧,输入在右侧。当标签不均匀时,输入的起点也是不均匀的,使外观更像是一级阶梯而不是整齐堆叠的表单。

但是,使用 CSS 网格,我们可以告诉包含输入标签的左列以max-content显示,而包含输入的右列则占据剩余的空间。

grid-template-columns: max-content 1fr;

不需要额外的元素或包装器!

等宽列

如果您使用fr单位来调整网格的列大小,则可用空间将在内容决定每列需要多少空间之后分配。如果您想要三个等宽列,您可能会想到这样做

grid-template-columns: 1fr 1fr 1fr;

这并不完全错误!但由于网格布局的最小尺寸是auto,它取决于内容的长度才能获得真正等宽的列。因此,我们通过在每列的minmax()函数中提供一个零值来删除最小尺寸,如下所示

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

浏览器支持

更多信息