理解 CSS 网格:网格线

已发表: 2022-03-10
快速总结 ↬在一个新系列中,Rachel Andrew 分解了 CSS 网格布局规范。 这次,我们来看看如何使用网格线来放置物品。

在本系列的第一篇文章中,我了解了如何创建网格容器以及应用于构成网格的父元素的各种属性。 一旦你有了一个网格,你就有了一组网格线。 在本文中,您将学习如何通过向网格容器的直接子项添加属性来将项目放置在这些行上。

我们将涵盖:

  1. 放置属性grid-column-startgrid-column-endgrid-row-startgrid-row-end及其简写grid-columngrid-row
  2. 如何使用grid-area按行号放置。
  3. 如何根据行名放置项目。
  4. 放置项目时隐式和显式网格之间的区别。
  5. 使用span关键字,带有一点额外的subgrid
  6. 混合自动放置和放置的物品时要注意什么。
  • 第 1 部分:创建网格容器
  • 第 2 部分:网格线
  • 第 3 部分:网格模板区域

基于线定位的基本概念

要将项目放置在网格上,我们设置它开始的行,然后是我们希望它结束​​的行。 因此,对于五列五行网格,如果我希望我的项目跨越第二和第三列轨道,以及第一、第二和第三行轨道,我将使用以下 CSS。 请记住,我们的目标是线路,而不是轨道本身。

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

这也可以指定为简写,正斜杠之前的值是开始行,m 之后的值是结束行。

 .item { grid-column: 2 / 4; grid-row: 1 / 4; }

在 CodePen 上,您可以看到示例,并更改项目跨越的行。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid Lines:放置速记。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid Lines:放置速记。

请注意,我们的盒子背景拉伸整个区域的原因是因为对齐属性align-selfjustify-self的初始值是拉伸的。

如果您只需要您的项目跨越一个轨道,那么您可以省略结束行,因为默认行为是项目跨越一个轨道。 我们在上一篇文章中自动放置项目时看到了这一点,每个项目进入一个单元格 - 跨越一列和一行轨道。 因此,要使项目从第 2 行跨越到第 3 行,您可以编写:

 .item { grid-column: 2 / 3; }

错过终点线也是完全正确的:

 .item { grid-column: 2; }

grid-area速记

您还可以使用grid-area放置项目。 我们将在以后的文章中再次遇到此属性,但是,当与行号一起使用时,它可以用于设置所有四行。

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

这些行号的顺序是grid-row-startgrid-column-startgrid-row-endgrid-column-end 。 如果使用横向语言,从左到右书写(如英语),那就是上、左、下、右。 您可能已经意识到这与我们通常在 CSS 中指定诸如边距之类的速记方式相反——它们依次为上、右、下、左。

这样做的原因是,无论您使用哪种书写模式或方向,网格都以相同的方式工作,我们将在下面详细介绍这一点。 因此,设置两个开始然后结束比将值映射到屏幕的物理尺寸更有意义。 我不倾向于将此属性用于基于行的放置,因为我认为grid-columngrid-row的二值简写在扫描样式表时更具可读性。

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

显式网格上的线

我在上一篇文章中提到了显式与隐式网格。 显式网格是您使用grid-template-columnsgrid-template-rows属性创建的网格。 通过定义列和行轨道,您还可以在这些轨道之间以及网格的开始和结束边缘定义线。

这些行已编号。 编号从块和内联方向的起始边缘的 1 开始。 如果您处于水平书写模式,句子从左侧开始并向右运行,这意味着块方向的第 1 行位于网格的顶部,而行内方向的第 1 行是左侧线。

项目显示在 Firefox Grid Inspector 突出显示行的位置
放置在网格上的项目

如果您使用水平 RTL 语言工作 - 就像使用阿拉伯语工作一样 - 块方向的第 1 行仍位于顶部,但内联方向的第 1 行位于右侧。

该项目现在从网格的右侧放置
与方向相同的位置:rtl

如果您在垂直书写模式下工作,并且在下图中我设置了writing-mode: vertical-rl ,那么在该书写模式下,第 1 行将位于块方向的开头,在这种情况下位于右侧。 内联方向的第 1 行位于顶部。

整个网格现在旋转了 90 度
书写模式下的相同位置:vertical-rl

因此,网格线与文档或组件的书写模式和脚本方向相关联。

显式网格的最后一行是数字-1并且行从该点开始倒数,使第-2行成为倒数第二行。 这意味着,如果您想跨越显式网格的所有轨道上的项目,您可以这样做:

 .item { grid-column: 1 / -1; }

隐式网格上的线

如果您创建了隐式网格轨迹,那么它们也从 1 开始计数。在下面的示例中,我为列创建了一个显式网格,但是,行轨迹已经在隐式网格中创建,我使用的是grid-auto-rows将这些大小调整为 5em。

具有placed类的项目已放置为从第 1 行到第 -1 行。 如果我们为两行使用显式网格,则该项目应跨越两行。 因为行轨迹是在隐式网格中创建的,所以第-1行解析为第 2 行,而不是第 3 行。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid Lines: explicit vs. implicit grids。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid Lines: explicit vs. implicit grids。

目前没有办法定位隐式网格的最后一行,不知道你有多少行。

根据命名行放置项目

在上一篇文章中,我解释了除了行号之外,您还可以选择命名网格上的行。 您可以通过在轨道大小之间的方括号内添加一个或多个名称来命名这些行。

 .grid { display: grid; grid-template-columns: [full-start] 1fr [main-start] 2fr 2fr [main-end full-end]; }

一旦你有一些命名的行,你可以在放置你的项目时将行号换成一个名称。

 .item { grid-column: main-start / main-end; } 

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid Lines:命名线。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid Lines:命名线。

如果您的行有多个名称,您可以在放置项目时选择您喜欢的任何一个,所有名称都将解析为同一行。

注意命名行时会发生一些有趣的事情。 查看我的文章“在 CSS 网格布局中命名事物”了解更多信息。

如果有多个同名的行会发生什么?

如果您有多个具有相同名称的行,您会得到一些有趣的行为。 如果您在repeat()表示法中命名行,就会发生这种情况。 在下面的示例中,我有一个 8 列网格,通过重复 4 次1fr 2fr模式创建。 我在较小的轨道sm和较大的轨道lg之前命名了这条线。 这意味着我有 4 行每个名称。

在这种情况下,我们可以使用名称作为索引。 因此,要放置一个从名为sm的第二行开始并延伸到名为lg的第三行的项目,我使用grid-column: sm 2 / lg 3 。 如果您使用不带数字的名称,则该名称将始终解析为具有该名称的第一行。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid Lines:命名线。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid Lines:命名线。

使用span关键字

在某些情况下,您知道您希望一个项目跨越一定数量的轨道,但是您不知道它在网格上的确切位置。 例如,您使用自动放置来放置项目,但希望它们跨越多个轨道而不是默认的 1。在这种情况下,您可以使用span关键字。 在下面的示例中,我的项目从auto行开始,这是自动放置放置它的行,然后它跨越 3 个轨道。

 .item { grid-column: auto / span 3; } 

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid Lines: span 关键字。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid Lines: span 关键字。

一旦我们广泛支持grid-template-columnsgrid-template-rowssubgrid值,这种技术将变得非常有用。 例如,在卡片具有标题和要在其中相互对齐的主要内容区域的卡片布局中,您可以使每张卡片跨越 2 行,同时仍然允许通常的自动放置行为。 各个卡片将使用subgrid作为它们的行(即每行有两行)。 如果您使用 Firefox,您可以在下面的示例中看到这一点,并阅读我的文章 CSS Grid Level 2: Here Comes Subgrid 以了解有关 subgrid 的更多信息。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid Lines: span 关键字和 subgrid。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid Lines: span 关键字和 subgrid。

/

带有 Firefox Grid Inspector 的卡片网格,显示它们分别位于网格的两行上
Firefox 中使用 Grid Inspector 的示例

使用基于行的放置对项目进行分层

网格将自动将项目放置到网格上的空单元格中,它不会将项目堆叠到同一个单元格中。 但是,通过使用基于行的放置,您可以将项目放入同一个网格单元中。 在下一个示例中,我有一个跨越两行轨道的图像,以及放置在第二个轨道中并具有半透明背景的标题。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid Lines:带有分层元素的卡片。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid Lines:带有分层元素的卡片。

项目将按照它们在文档源中出现的顺序堆叠。 所以在上面的例子中,标题出现在图像之后,因此显示在图像的顶部。 如果标题先出现,那么它最终会显示在图像后面,我们将无法看到它。 您可以使用z-index属性控制此堆叠。 如果标题在源中排在第一位很重要,那么您可以使用z-index ,标题的值高于图像。 这将强制标题显示在图像顶部,以便可以阅读。

混合基于行和自动放置

如果您将放置的物品与自动放置的物品混合在一起,则需要格外小心。 当项目完全自动放置在网格中时,它们将按顺序将自己放置到网格上,每个都找到下一个可用的空白空间来放置自己。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid Lines: auto-placement。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid Lines: auto-placement。

默认行为总是向前推进,如果项目不适合网格,则留下一个间隙。 您可以通过使用值为dense的属性grid-auto-flow来控制此行为。 在这种情况下,如果有一个项目适合网格中已经留下的空白,它将按照源顺序放置以填补空白。 在下面使用密集包装的示例中,项目 3 现在放置在项目 2 之前。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid Lines: auto-placement and dense packing。

请参阅 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid Lines: auto-placement and dense packing。

请注意,此行为可能会导致在文档中切换的用户出现问题,因为视觉布局将与他们遵循的源顺序不同步。

如果您已经放置了一些物品,自动放置的工作方式会略有不同。 放置的物品将首先被定位,然后自动放置将寻找第一个可用的间隙以开始放置物品。 如果您通过空网格行在布局顶部留下了一些空白,然后引入一些自动放置的项目,它们将最终出现在该轨道中。

为了在最后一个示例中进行演示,我放置了基于行的定位属性,项目 1 和 2 将第一行留空。 后来的项目已经向上移动以填补空白。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid Lines:自动放置与放置的项目混合。

请参阅 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid Lines:自动放置与放置的项目混合。

这种行为值得理解,因为如果您在布局中引入一些尚未在网格上放置的新元素,这可能意味着项目最终会出现在奇怪的位置。

包起来

这几乎就是您需要了解的有关网格线的所有信息。 请记住,您总是有编号的行,无论您如何使用网格,您始终可以将项目从一个行号放置到另一个行号。 我们将在以后的文章中介绍的其他方法是指定布局的替代方法,但基于由编号线创建的网格。

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