调试CSS网格
第1部分:了解隐含的轨道
当观察人们掌握CSS Grid时,我注意到一些问题比其他问题更容易引起人们的注意,或者在构建布局时遇到更多挑战。这一系列简短的文章将深入研究这些常见问题,旨在更好地理解网格,以便您可以预测布局问题,并在发生问题时更轻松地进行调试。
意外的隐含轨迹
我见过的最让人困扰的问题是无意中创建了额外的网格轨道,这可能会使整个布局陷入混乱。这些额外的轨道称为隐式轨道,它们是通过将项目放置在显式网格边界之外来创建的。为了充分利用Grid,理解显式和隐式网格的概念以及它们之间的关系是个好主意。
显式网格
使用grid-template-rows
和grid-template-columns
属性定义显式网格(grid-template
如果您愿意,还可以使用简写):
.grid {
display: grid;
grid-template-rows: repeat(4, 150px);
grid-template-columns: repeat(4, 1fr);
}
在这里,我们定义了一个包含四行四列的网格,我们可以知道我们的网格至少有四行四列,无论如何。即使我们没有任何网格子项放置,以便我们的网格完全为空,它仍将占用我们在上面定义的四行四列的空间。
如果我们使用repeat(4, auto)
的grid-template-rows
财产,我们的网格行都会有一个高度auto
-所以,如果我们没有电网的孩子那么我们的行仍然存在,他们只会崩溃下降到零的高度没有任何内容,以填补他们。如果我们添加了一个行间隙(例如row-gap: 40px
),那么行之间的间隙的组合高度将构成我们网格的高度 – 因此,如果没有任何内容,它可能看起来像是一个超大的边距或填充值,这会破坏您的布局!
什么是隐含的轨道?
隐式曲目是仅通过放置项目创建的曲目。Grid中的这种行为是有意的,非常有用。例如,如果您有一个包含四列的网格,我们要填充不确定数量的项目(例如新闻Feed。如果我们不知道项目数量,我们将不知道我们需要多少行网格。默认情况下,网格项放在下一个可用的网格单元格中。我们可以简单地省略grid-template-rows
属性并允许Grid的自动放置为我们的内容创建正确的行数。
(旁注:我假设网格使用的是默认值grid-auto-flow: row
。如果更改为此,grid-auto-flow: column
则会在行轴上创建隐式轨迹。)
.grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
}
我们可以使用grid-auto-rows
和控制隐式轨道的行为grid-auto-columns
。
.grid {
display: grid;
grid-template-rows: repeat(4, 150px);
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 150px;
}
上面的代码除了定义四个显式的列和行轨道外,还指示Grid创建的任何隐式行轨道应具有150px的固定高度。此属性是可选的,没有它,任何隐式轨道的默认大小都是auto
。
放置物品
要在我们刚刚创建的网格上放置一个项目,我们可以这样做:
.item {
grid-column: 1 / 4;
grid-row: 3 / 5;
}
我们使用起点和终点线将网格项放在网格的左下角。
这不会导致任何问题,因为我们通过网格线号显式放置项目。我们知道我们的网格有四行四列(因此在任一方向上都有五个网格线),因此我们不小心意外地无意中使用了更高的行号并意外地创建了隐含的轨迹。
或者,我们可以使用span关键字代替起点或终点:
.item {
grid-column: 1 / 4;
grid-row: 3 / span 3;
}
我喜欢span
用于网格放置 – 当你知道一个项目需要跨越一定数量的网格轨道而不是在一个特定的行结束时,它通常很有用 – 但这意味着你有时会忘记你放置的网格线项目。
我们在这里用来span
代替这grid-row-end
条线。如果我们将span值更改为4而不是3,这将导致项目跨越更多行轨道而不是可用 – 并且哎呀!我们创造了一个隐含的轨道!
我发现在需要网格项相互重叠的情况下,这种问题经常发生。这是因为Grid放置未明确放置在下一个可用网格单元格中的项目,如果没有可用的网格单元格,则它将创建隐式轨道而不是堆叠项目。这种行为非常有用,因为这意味着我们并不总是需要明确地放置项目,但这是一个对我们没有特别帮助的情况!
我的一个朋友正在使用Grid来定位两个元素,一个在另一个上面,但是偏移了一行:
这是用于创建布局的代码:
.grid {
grid-template-columns: repeat(3, 1fr);
}
.item:first-child {
grid-column: span 3;
grid-row: 1 / span 2;
}
.item:nth-child(2) {
grid-column: span 3;
grid-row: 2 / span 2;
}
我们得到这个:而不是所需的布局:
第二项发生了什么事?你能在这里发现问题吗?这两个项目都使用span关键字作为grid-column
值。第一个项目将被正确定位,因为它将自动放置在第一个可用单元格中,跨度为3.第二个项目没有开始或结束行,因此Grid需要解决此问题,它通过生成隐式列轨道。
如果网格有四个显式行,那么该项将换行到下一行(这不是我们想要的布局,但可能不那么令人困惑!),但由于它们没有足够的可用行,所以Grid解析了这个将项目从第5行开始放在列轴上并生成四个隐含轨道。因为我们不是grid-auto-columns
用来为隐式轨道定义大小,所以它们的默认大小为auto
。如果网格项没有内容,那么这些轨道将向下折叠到宽度0,从而使我们的项目不可见。我们的网格项包含一个标题,因此这些隐式轨道将自动调整大小以适应这种情况。
如果我们有一个column-gap
值,比方说,20px
我们会看到两个列间隙的宽度被添加到我们的网格中,尽管轨道本身将为零。
使用下面的演示来探索“打破”布局的不同方法:
防止我们的布局中断
那么,我们怎样才能最好地避免遇到隐含轨道的问题呢?一种方法是了解Grid如何在幕后计算我们的布局。
了解网格项目放置算法
这听起来比实际上更可怕!该网格项目布局算法是其中的网格项目的安置解决的顺序。首先显式定位的网格项,然后是具有明确行位置的项,然后确定隐式网格中的列,并相应地放置任何自动放置的项(没有明确位置的项)。这是假设grid-auto-flow
属性值是row
(默认值)。牢记这一点可以帮助您理解为什么您可能在一个轴而不是另一个轴上创建隐式轨道,如果这与您的期望相反。
我还提供了一些关于放置物品的方法的提示,而不是帮助避免意外地将物品从显式网格中推出……
命名网格线
有一种方法可以帮助我更有意识地使用网格布局来命名网格线。假设我们要放置的项目是图像。我们可以这样做:
.grid {
display: grid;
grid-template-rows:
repeat(2, 150px) [image-start] repeat(2, 150px)
[image-end];
grid-template-columns: [image-start] repeat(3, 1fr) [image-end] 1fr;
grid-auto-rows: 150px;
}
使用-start和-end作为行名称的后缀会创建一个网格区域,这使得放置图像变得非常简单:
.image {
grid-area: image;
}
您也可以使用该grid-template-areas
属性执行类似的操作,这对许多人来说感觉更直观 – 请记住,如果您需要重叠的网格项,这将无法工作。
按终点排列
有时按结束行号(而不是起始行号)放置可以帮助避免创建意外隐含轨道的问题。以上面的例子为例,我们可能知道我们希望图像跨越三个网格轨道,因此我们使用span关键字作为grid-column-end
值。但是使用span作为grid-column-start
值并将其显式放在其结束行上可能会更好:
.image {
/* The image will end at line 4 on the column axis: */
grid-column: span 3 / 4;
}
如果我们有一个非常大的网格,这可能会有所帮助。想象一下,我们的网格有20列而不是只有4列,我们可能知道它需要距离末端一行,但我们不想每次计算起始线应该是什么 – 这会很烦人而且容易出错!
负网格线
我觉得非常有用的技术(以及之前我写过的东西)是使用负线数来放置网格项。负线数反向表示网格线。因此,在四个轨道的网格中(其将具有五个网格线),线-1相当于线5,线-2相当于线4,依此类推。
同样,在使用大型网格时,这可以非常方便。如果我们知道并且项目需要与网格的末尾对齐,那么我们可以简单地使用网格线-1,而不是必须记住最后一行是第21行。
使用开发工具进行调试
我完全推荐使用Firefox开发工具来检查和调试CSS Grid的问题。该网格检查可以让你的行号切换,所以即使你的隐含的轨道的大小已经倒塌一直到零,你仍然能够看到他们已经建立。(检查员还会向您显示负数 – 非常方便!)
结论
我希望这篇文章在使用CSS Grid时能够揭开隐秘与显式轨迹的神秘面纱,并为您提供一些有价值的知识来帮助您调试损坏的布局。请关注调试CSS网格系列中的更多文章。