带有 CSS 网格和命名列的编辑设计模式
已发表: 2022-03-10许多网站,尤其是那些显示长篇内容的网站,都有相当简单的重复组件模式:图像的全角区域、中心内容区域,可能还有两个半角块的拆分视图。 这些组件重复显示文章、图像和其他相关内容——内容编辑在创建文章以供发布时选择正确的组件。
在本文中,我将展示这种编辑设计的方法,它建立在一些技术的基础上,其中一些将在以下文章中讨论:
- “用 CSS 网格布局突围”
- “用 CSS Grid 突围解释”
- “在 CSS 网格布局中命名事物”
除了这是一种命名布局部分的好方法之外,这种技术还公开了一大堆关于网格布局的有趣内容,您可能会发现它们在创建自己的布局模式时很有用。 它还展示了 subgrid 的更多承诺(即将到来的第 2 级网格规范的一部分,并在 Firefox 中实现)。
在 CSS 网格布局中命名事物
使用 CSS 网格布局时,您可以命名线条和区域。 这两件事都可以使使用网格——尤其是复杂的网格——更加直接。 与团队合作时,为布局中的事物定义命名约定可能很有用; 与从column-line: 3 / 9
放置的东西相比,使用grid-area: content
放置的东西最终会更容易理解。
使用grid-template-areas
方法时,您可以使用grid-area
属性为要放置在网格上的项目命名,然后将它们放置在网格周围。 在以下示例中,带有grid-area: content
的项目进入由grid-template-areas
属性定义的网格区域:
请参阅 Rachel Andrew 的 Pen [Layout With Named Area](https://codepen.io/rachelandrew/pen/zYOQBba)。
这适用于您将一件物品放入一个区域的组件。 但是,如果您想将多个东西放入内容区域(一个在另一个之下),则使用grid-area
是错误的方法。 相反,您可以为列行定义名称并将项目从开始行放置到结束行。
请参阅 Rachel Andrew 的 Pen [带有命名列的布局](https://codepen.io/rachelandrew/pen/xxKNONQ)。
然而,当使用网格区域方法时,当使用grid-column
或grid-row
放置项目时,我们必须知道开始线和结束线,这不是那么整洁 - 或者我们吗?
看看下一个 CodePen 示例。 我的项目通过使用grid-column
属性使用单个名称或标识放置,即使某些目标网格区域跨越多个列:
请参阅 Rachel Andrew 的 Pen [带有命名列的布局](https://codepen.io/rachelandrew/pen/mdbYEod)。
我的目标是在实际使用网格时抽象出网格设置的复杂性。 我可以投入大量工作来创建初始网格,然后在填充页面时无需过多考虑就可以放置东西。 我还想确保我们可以在构建文章时尽可能频繁地重复这些组件。 我想到的是使用 CMS 的内容创建者,并使用不同的模式创建内容块,同时知道它们将在整个网格上正确地放置在另一个之下。
为了理解我是如何走到这一步的,需要了解一些关于 CSS 网格布局以及命名线和区域的知识。
我们可以命名线路
正如您在上面的第二个示例中已经看到的那样,我们可以在网格上命名几乎任何我们喜欢的线条——除了单词span
。 该名称是一个标识而不是一个字符串,这就是它不被引用的原因。
但是,您将看到许多使用命名约定name-start
和name-end
的示例,它们将-start
附加到起始行的名称上,将-end
附加到结束行的名称上。 这不是纯粹的约定,对于我将向您展示的技术,为什么我们需要以这种方式命名我们的行。 因此,您应该为所描述的区域选择一个名称,然后添加-start
和-end
后缀——当然,它们需要匹配!
我们在方括号内命名我们的行。 行可以(并且经常需要)有多个名称。 在这种情况下,空格分隔名称。 使用基于线的定位放置项目时,您可以为线选择任何名称来进行放置。
有了我们的命名行,我们可以通过指定开始和结束行名称来使用grid-column
放置我们的项目。 此模式与使用行号相同,因此斜线之前的名称是起始行,斜线之后的名称是结束行。
请参阅 Rachel Andrew 的 Pen [使用开始和结束行的示例](https://codepen.io/rachelandrew/pen/VwZOPgO)。
这放置了项目,但不是我在示例中使用的每个项目的整洁单一名称。 但是,由于 Grid 处理命名区域和线的特殊方式,我们现在已经准备就绪。
线路名称给我们一个命名区域
假设你像我一样用-start
和-end
命名你的行,Grid 会给你一个你使用的主要名称的命名区域。 因此,就我而言,我有名为content
、 start-half
、 end-half
、 full
和center
的区域。 这些区域中的每一个都是单行(因为我没有命名行),但是,它将跨越从-start
到-end
行的列轨道。
命名区域为我们提供了使用的主要名称的命名行
如果我们希望能够像有列名一样放置我们的项目,我们还需要利用这样一个事实,即在创建网格区域时,我们会获得所使用的主要名称的行名; 也就是说,主名称是删除了-start
和-end
的名称。 此行名称解析为区域的开始或结束,具体取决于我们的目标是grid-column-start
还是grid-column-end
。

因此,我们有一个名为content
的区域,因为我们有名为content-start
和content-end
的列行。 名为content
的区域还使我们能够使用grid-column-start: content
将解析到该内容区域的起始行,而grid-column-end: content
将解析到内容区域的结束行。
因此,这意味着我们可以使用以下命令将项目放入内容区域:
.content { grid-column: content / content; }
接下来,我们现在可以进一步整理这项技术,因为如果您使用命名行作为grid-column-start
并省略结束行(而不是像使用行号那样跨越一个轨道),网格将名称复制到结束行。 因此, grid-column: content
与grid-column: content / content;
这就是我们需要能够使用具有简单单一名称的grid-column
放置项目的全部内容。 这种行为完全符合规定,而不是某种“黑客”。 它展示了创建 Grid Layout 规范的深度思考,以及为使我们的设计中的项目布局变得如此简单而投入的大量细致工作。
使用 Subgrid 赋予该技术超能力
我认为这种技术是一种很好的技术,它能够以一种非常直接的方式来声明元素应该放置在网格上的什么位置。 但是,如果我们在混合中添加子网格支持,它确实会变得非常强大。
目前,subgrid 正在 Firefox 中实现,因此接下来的这些示例需要 Firefox Nightly 才能运行。 你可以在这里下载 Nightly。
grid-template-columns
和grid-template-rows
的subgrid
值意味着在父网格上创建的大小可以由作为网格子项的项目(假设它也使用网格布局)通过display: grid
应用display: grid
。
注意:您可以在 Smashing Magazine “CSS Grid Level 2: Here Comes Subgrid” 和 “Digging In the Display Property: Grids All Way Down” 上的文章中阅读更多关于 subgrid 功能的信息。
父项中的线名被传递到子网格中
除了将轨道尺寸信息传递到子网格之外,在父网格上设置的任何线名都将被传递。这意味着我们可以在子网格组件中使用我们的“列名”,使得这个解决方案在一个世界中非常有用子网格存在。 放置在content
中的项目——即使嵌套在子网格内——将与作为主网格的直接子级放置的项目对齐。
在下一个示例中,我将两个元素直接嵌套在 div 中,类为full-2
。 我还在.content
中放置了一个ul
。 如果我们查看full-2
中的项目,为了将它们放置在父网格上,我们需要使选择器full-2
成为具有display: grid
的网格,然后使用值为subgrid
的grid-template-columns
属性.
这会导致.full-2
上的网格使用父网格上定义的轨道,并可以访问那里定义的命名线。 由于这是一个全宽项目,因此在放置我们的项目方面,它的行为实际上就像父网格一样。 然后,我们可以使用为不同列定义的任何名称来放置项目。 在这种情况下,我将两个子元素都设置为grid-column: center
并且它们在该中心区域中一个接一个地显示。
.full-2 { grid-row: 4; grid-column: full; display: grid; row-gap: 10px; grid-template-columns: subgrid; } .full-2 > div { background-color: rgb(124,222,220); grid-column: center; }

如果我们看一下嵌套在.content
中的ul
,我们需要在选择器.content
上创建一个子网格,就像上一个示例一样; 当我们这样做时, ul
落入子网格的第一个轨道。 如果我们想在 subgrid 上布置监听项,我们需要做两件事:通过放置 ul 与它的 parent 占用相同的区域grid-column: content
,然后使其成为一个网格,即一个子网格。
完成此操作后,列表项将使用自动放置到子网格的列轨道中进行布局:
.content { grid-row: 1; grid-column: content; display: grid; grid-template-columns: subgrid; } .content ul { grid-column: content; display: grid; row-gap: 10px; grid-template-columns: subgrid; }

一旦你有了你的网格,你就可以像以前一样使用父级的名称。
.content li:nth-child(1) { grid-column: center; } .content li:nth-child(2) { grid-column: start-half; } .content li:nth-child(3) { grid-column: end-half; } .content li:nth-child(4) { grid-column: content; }

如果你有 Firefox Nightly,你可以在这个 CodePen 示例中看到完整的演示:
请参阅 Rachel Andrew 的 Pen [命名列和子网格](https://codepen.io/rachelandrew/pen/OJLYRRb)。
您可以像这样将“嵌套”子网格保留到您的标记结构中,并且每次都会传递行名称。 这是一个我认为会特别有用的功能。
创建子网格时,行号对应于子网格的线,而不是父网格。 因此,如果您确实想确保子网格中的元素与父网格对齐,那么使用线名或命名区域(如本例所示)将使这变得简单而合乎逻辑。
包起来
您现在知道如何将这种技术用于您的主网格,并且希望用不了多久我们就会开始在所有浏览器中看到对子网格的支持。 它将启用诸如此类的技术,并使其非常强大,供我们使用。