了解 CSS 网格:创建网格容器

已发表: 2022-03-10
快速总结 ↬在一个新系列中,Rachel Andrew 分解了 CSS 网格布局规范。 这一次,我们将详细了解创建网格容器时会发生什么,以及可应用于容器以塑造网格的各种属性。

这是 Smashing Magazine 专注于 CSS 网格布局的新系列的开始。 虽然自 2017 年以来 Grid 已在浏览器中可用,但许多开发人员还没有机会在项目中使用它。 似乎有很多与 CSS 网格布局相关的新属性和值。 这可以使它看起来势不可挡。 但是,很多规范详细说明了做事的替代方法,这意味着您不必学习整个规范即可开始使用。 本系列旨在将您从网格新手转变为专家 - 在此过程中提供许多实际使用技巧。

这篇最初的文章将介绍创建网格容器时会发生什么,以及可以在父元素上使用来控制该网格的各种属性。 您会发现有几个用例仅通过您应用于网格容器的属性来实现。

在本文中,我们将介绍:

  • 使用display: griddisplay: inline-grid创建一个网格容器,
  • 使用grid-template-columnsgrid-template-rows设置列和行,
  • 使用grid-auto-columnsgrid-auto-rows控制隐式轨道的大小。

  • 第 1 部分:创建网格容器

  • 第 2 部分:网格线

  • 第 3 部分:网格模板区域

跳跃后更多! 继续往下看↓

创建网格容器

Grid 和 Flexbox 一样,是 CSS display属性的一个值。 因此,要告诉浏览器您要使用网格布局,请使用display: grid 。 完成此操作后,浏览器将为您提供带有display: grid的元素上的块级框,并且任何直接子级都将开始参与网格格式化上下文。 这意味着它们的行为类似于网格项,而不是普通的块和内联元素。

但是,您可能不会立即在页面上看到差异。 由于您尚未创建任何行或列,因此您有一个单列网格。 正在生成足够的行来容纳所有直接子级,并且它们在该单列中一个接一个地显示。 从视觉上看,它们看起来就像块元素。

如果您有任何未包含在元素中的文本字符串以及网格容器的直接子元素,您将看到不同之处,因为该字符串将被包含在匿名元素中并成为网格项。 任何通常是内联元素的元素,例如 span,一旦其父元素是网格容器,也将成为网格项。

下面的例子有两个块级元素,加上一个文本字符串,字符串中间有一个跨度。 我们最终得到五个网格项目:

  • 两个div元素,
  • 跨度之前的文本字符串,
  • 跨度,
  • 跨度之后的文本字符串。

请参阅钢笔网格容器:直接子元素和文本字符串成为 Rachel Andrew (@rachelandrew) 在 CodePen 上的网格项。

请参阅钢笔网格容器:直接子元素和文本字符串成为 Rachel Andrew (@rachelandrew) 在 CodePen 上的网格项。

如果您使用 Firefox Grid Inspector 检查网格,您可以看到已为项目创建的五行轨道。

具有五行的单列网格
Grid Inspector 可帮助您查看已创建的行数

您还可以使用display: inline-grid创建内联网格; 在这种情况下,您的网格容器将成为一个内联级框。 但是,直接子项仍然是网格项,其行为方式与块级框内的网格项相同(它只是外部显示类型)。 这就是为什么当网格容器与页面上的其他框并排时,它的行为方式与上面一样。

下一个示例有一个网格,后跟一个文本字符串,因为这是一个内联网格,文本可以显示在它旁边。 内联级事物不会像块级事物那样拉伸以占用内联维度中的所有空间。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid Container:inline-grid。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid Container:inline-grid。

注意将来,我们将能够更好地描述我们的布局,使用display: block grid来创建我们的块级容器,使用display: inline grid来创建一个内联级容器。 您可以在我的文章“深入了解 DISplay 属性:Display 的两个值”中了解对显示规范的这种更改。

列和行

为了得到看起来像网格的东西,我们需要添加列和行。 这些是使用grid-template-columnsgrid-template-rows属性创建的。 这些属性在规范中定义为接受一个称为track-list的值。

这些属性以空格分隔的轨道列表的形式指定网格的行名称和轨道大小功能。 grid-template-columns 属性指定网格列的轨道列表,而 grid-template-rows 指定网格行的轨道列表。

一些有效的曲目列表值如下:

grid-template-columns: 100px 100px 200px; 创建一个三列网格:第一列是 100px,第二列是 100px,第三列是 200px。
grid-template-columns: min-content max-content fit-content(10em) 创建一个三列网格:第一列是该轨道的min-content大小,第二列是max-content大小。 第三个是max-content ,除非内容大于 10em,在这种情况下,它被限制为 10em。
grid-template-columns: 1fr 1fr 1fr; 使用fr单位创建一个三列网格。 网格容器中的可用空间被分成三部分,并在三列之间共享。
grid-template-columns: repeat(2, 10em 1fr); 创建一个四列网格,其重复模式为10em 1fr 10em 1fr ,因为 repeat 语句中的 track-list 重复了两次。
grid-template-columns: repeat(auto-fill, 200px); 如果有空闲空间,则使用尽可能多的 200px 列填充容器,在最后留下一个间隙。
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); 用尽可能多的 200px 列填充容器,然后在创建的列之间平均分配剩余空间。
grid-template-columns: [full-start] 1fr [content-start] 3fr [content-end] 1fr [full-end]; 创建一个三列网格:第一列和第三列各有 1 部分可用空间,而中间列有 3 部分。 通过将行名放在方括号中来命名行。

如您所见,有很多方法可以创建曲目列表! 让我们来看看这些都是如何工作的,并提供一些提示,说明您为什么要使用它们。

使用长度单位

您可以使用任何长度单位或百分比来创建曲目。 如果轨道的大小加起来小于网格容器中可用的大小,则默认情况下,轨道将在容器的开始处排列,备用空间将到最后。 这是因为align-contentjustify-content的默认值是start 。 您可以使用对齐属性将网格轨道隔开,或者将它们移动到容器的末尾,我在我的文章“如何在 CSS 中对齐事物”中对此进行了详细说明。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid Container:长度单位。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid Container:长度单位。

您还可以使用关键字min-contentmax-contentfit-content() 。 使用min-content将为您提供尽可能小的轨道而不会导致溢出。 因此,当用作列大小时,内容将尽可能软换行。 轨道成为列中最长单词或最大固定大小元素的大小。

使用max-content将导致内容根本不进行任何软包装。 在列中,任何文本字符串都会展开,这可能会导致溢出。

fit-content关键字只能通过传入一个值来使用。 该值成为该轨道将增长到的最大值。 因此,轨道将像max-content一样,内容展开并伸展,直到达到您传入的值。此时,它将开始正常换行。 所以你的轨迹可能小于你传入的值,但永远不会更大。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid Container:min-content、max-content、fit-content()。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid Container:min-content、max-content、fit-content()。

您可以在我的文章“那个盒子有多大? 了解 CSS 布局中的大小调整”。

如果您最终得到的轨道占用的空间超过容器中的空间,它们就会溢出。 如果你使用百分比,那么与基于百分比的浮动或弹性布局一样,如果你想避免溢出,你需要注意总百分比不超过 100%。

fr单位

Grid Layout 包含一种可以让您自己计算百分比的方法——使用fr单位进行轨道大小调整。 该单位不是长度,因此不能与calc()结合使用; 它是一个弹性单元,代表网格容器中的可用空间。

这意味着使用1fr 1fr 1fr的曲目列表; 可用空间分为三个,并在轨道之间平均共享。 使用2fr 1fr 1fr的轨道列表,可用空间分为四部分,两部分分配给轨道一——轨道二和三各有一部分。

请参阅 CodePen 上的 Pen Grid Container:Rachel Andrew (@rachelandrew) 的 fr。

请参阅 CodePen 上的 Pen Grid Container:Rachel Andrew (@rachelandrew) 的 fr。

需要注意的是,默认情况下共享的是可用空间,而不是容器中的总空间。 如果您的任何曲目包含固定大小的元素或无法换行的长单词,则将在空间共享之前对其进行布局。

在下一个示例中,我删除了ItemThree单词之间的空格。 这形成了一个长而牢不可破的字符串,因此空间分配发生在该项目的布局被考虑之后。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid Container:fr 与更大的内容。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid Container:fr 与更大的内容。

您可以将fr单元与固定长度的轨道混合,这就是它变得非常有用的地方。 例如,您可以拥有一个具有两个固定大小的列和一个可伸展的中心区域的组件:

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid Container:混合 fr 单位和固定大小的轨道。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid Container:混合 fr 单位和固定大小的轨道。

您可以将一个轨道设置为fit-content(300px)并将另一个轨道设置为 1fr。 这使得组件在第一个轨道中可以有小于 300px 的东西,在这种情况下,它只占用它需要的空间,而fr单元扩展以占用其余空间。

如果您添加更大的内容(例如具有max-width: 100%的图像),第一个轨道将在 300px 处停止增长,而fr单元将占据其余空间。 将fr单元与 fit-content 混合是一种为您的站点制作一些非常灵活的组件的方法。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid Container:混合 fr 和 fit-content()。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid Container:混合 fr 和 fit-content()。

重复()函数

在您的曲目列表中使用repeat()可以节省一遍又一遍地输入相同的值或值。 例如以下两行是相同的:

 grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr; grid-template-columns: repeat(12, 1fr);

使用repeat()时,逗号之前的值是重复逗号之后的曲目列表的次数。 该曲目列表可以是多个值。 这意味着您可以重复轨道模式。

您可以将repeat()函数用于曲目列表的一部分。 例如,以下行将为您提供 1fr 轨道、3 200px 轨道和最终 1fr 轨道。

 grid-template-columns: 1fr repeat(3,200px) 1fr

除了逗号前的数字表示固定的重复次数外,还可以使用关键字auto-fillauto-fit 。 使用这些关键字之一意味着您的网格容器将填充尽可能多的轨道,而不是固定数量的轨道。

请参阅钢笔网格容器:Rachel Andrew (@rachelandrew) 在 CodePen 上的自动填充。

请参阅钢笔网格容器:Rachel Andrew (@rachelandrew) 在 CodePen 上的自动填充。

使用固定长度单位意味着,除非容器能够准确地除以该大小,否则您最终会剩下一些空闲空间。 在上面的例子中,我的容器是 500px 宽,所以我得到了两个 200px 的轨道加上最后的空间。

我们可以使用另一个网格函数来使该值最小化,任何空闲空间都分布在所有轨道上。 minmax()函数采用最小和最大大小。 最小 200px 和最大 1fr,我们可以得到尽可能多的 200px 轨道,因为最大值是 1fr,我们已经知道这将平均分配空间,额外的分配在轨道上。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid Container:auto-fill 和 minmax()。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid Container:auto-fill 和 minmax()。

我提到有两个可能的关键字: auto-fillauto-fit 。 如果您有足够的内容来填充第一行单元格,那么这些单元格的行为方式将完全相同。 但是,如果您不这样做(例如,如果我们在上面的容器中删除了除一项之外的所有项目),那么它们的行为会有所不同。

即使没有内容进入,使用auto-fill将保持可用的轨道大小。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid Container: auto-fill and minmax() with one item。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid Container: auto-fill and minmax() with one item。

相反,如果您使用auto-fit ,则空轨道将被折叠:

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid Container: auto-fit 和 minmax() 以及一项。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid Container: auto-fit 和 minmax() 以及一项。

通过使用 Firefox Grid Inspector,您可以看到轨道仍然存在,但已折叠为零。 我们网格的终点线仍然是第 3 行,因为我们可以容纳两条轨道。

单个网格项填充容器,网格检查器突出显示列线
轨道还在,但倒塌了

命名线

我上面的最后一个示例使用了命名行方法。 使用网格时。 你总是有行号,但是,你也可以命名这些行。 行在方括号内命名。 一行可以有多个名称; 在这种情况下,一个空格将它们分开。 例如,在以下曲目列表中,我的所有行都有两个名称。

 grid-template-columns: [main-start sidebar-start] 1fr [sidebar-end content-start] 4fr [content-end main-end]

您可以将您的行命名为您喜欢的任何名称,除了span一词,因为它是一个保留字,因为在将项目放置在网格上时会使用它。

注意在本系列的下一篇文章中,我将更多地讨论基于行的放置以及如何使用命名行。 同时,请阅读我关于“在 CSS 网格布局中命名事物”的文章,以帮助您了解有关该主题的更多信息。

显式与隐式网格

使用带有轨道列表的grid-template-columnsgrid-template-rows创建网格时,您正在创建所谓的显式网格。 这是您定义的网格,它具有您为每个轨道选择的大小。

如果您的项目多于无法容纳的数量,或者将项目放置在您创建的网格边界之外,则 Grid 将在隐式网格中创建轨道。 默认情况下,这些隐式轨道将自动调整大小。 当我声明display: grid父元素上的网格和网格创建的行,每个项目一个。 我没有定义这些行,但由于有网格项目,所以创建行轨道是为了让它们有去处。

您可以使用grid-auto-rowsgrid-auto-columns属性设置隐式行或列的大小。 这些属性采用跟踪列表,因此如果您希望所有隐式列的高度至少为 200 像素,但如果内容更多则增加,您可以使用以下内容:

 grid-auto-rows: minmax(200px, auto)

如果您希望第一个隐式行自动调整大小,第二个是min-content大小,依此类推(直到所有网格项目都已容纳),您可以传入多个值:

grid-auto-rows: auto 100px

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid Container:grid-auto-rows。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid Container:grid-auto-rows。

使用具有自动放置功能的网格

创建一个网格(并允许浏览器自动放置项目)在您可以实现的有用模式方面让您有很长的路要走。 我们还没有考虑在网格上放置项目,但是许多使用 Grid 的布局不做任何放置。 他们只是依赖于将项目按源顺序排列——每个网格单元中都有一个。

如果您是 CSS Grid 的新手,那么使用不同的轨道大小并查看项目如何将自己放置到您创建的单元格中是一个很好的开始方式。

  • 第 1 部分:创建网格容器
  • 第 2 部分:网格线
  • 第 3 部分:网格模板区域