许多应用场景都需要在网格中显示可选择的项目,例如日历、购物车、图库、文件浏览器和在线图书馆,甚至那些要求你选择所有带有斑马线的图片的安全检查。
本文介绍一种巧妙的方法来显示网格中的可选项目,并非重新创建 reCAPTCHA,而是能够选择多个项目。当选择两个或多个相邻项目时,我们可以巧妙地使用 :nth-of-type
组合器、伪元素和 :checked
伪类来设计它们,使它们看起来组合在一起。
这种组合器和伪元素来实现圆角复选框的想法源于我之前写的一篇文章。那是一个简单的单列设计:
然而,这一次,圆角效果应用于网格上垂直和水平轴上的元素。你不需要阅读我关于复选框样式的上一篇文章,因为我将在这里涵盖你需要知道的一切。但是,如果你对本文中所做内容的简化版本感兴趣,那么那篇文章值得一看。
注意以下几点将非常有用。例如,为了简单起见,我在我的演示中使用了静态 HTML 和 CSS。根据你的应用程序,你可能需要动态生成网格及其中的项目。为了专注于效果,我省略了辅助功能的实际检查,但在生产环境中,你肯定需要考虑这类事情。
此外,我使用 CSS Grid 进行布局。我推荐这样做,但这只是一个个人偏好,你的体验可能会有所不同。对我来说,使用网格允许我轻松使用同级选择器来定位项目的 ::before
和 ::after
伪元素。
因此,无论你可能想要在你的应用程序中使用什么布局标准,请确保伪元素仍然可以在 CSS 中被定位,并确保布局在不同的浏览器和屏幕上保持不变。
正如你在之前的演示中可能注意到的那样,选中和取消选中复选框元素会修改框的设计,具体取决于周围其他复选框的选择状态。这是因为我使用相邻元素的伪元素而不是它自己的元素来设置每个框的样式。
下图显示了每个列(第一列除外)中框的 ::before
伪元素如何与它们左侧的框重叠,以及每个行(第一行除外)中框的 ::after
伪元素如何与上面的框重叠。
标记非常简单:
<main></main>
初始 CSS 中还有更多内容。但是,首先是网格本身:
/* 网格 */ main { display: grid; grid: repeat(5, 60px) / repeat(4, 85px); align-items: center; justify-items: center; margin: 0; }
这是一个包含复选框的五行四列的网格。我决定清除复选框的默认外观,然后赋予它们我自己的浅灰色背景和超圆角边框:
/* 所有复选框 */ input { -webkit-appearance: none; appearance: none; background: #ddd; border-radius: 20px; cursor: pointer; display: grid; height: 40px; width: 60px; margin: 0; }
还要注意,复选框本身也是网格。这是放置其 ::before
和 ::after
伪元素的关键。说到这里,让我们现在就做吧:
/* 除第一列和第一行外的伪元素 */ input:not(:nth-of-type(4n 1))::before, input:nth-of-type(n 5)::after { content: ''; border-radius: 20px; grid-area: 1 / 1; pointer-events: none; }
我们只选择不在网格第一列或第一行的复选框的伪元素。input:not(:nth-of-type(4n 1))
从第一个复选框开始,然后选择从那里开始的每四个项目的 ::before
。但是请注意我们说的是 :not()
,所以实际上我们所做的是跳过从第一个开始的每个第四个复选框的 ::before
伪元素。然后,我们从第五个复选框开始,将样式应用于每个复选框的 ::after
伪元素。
现在我们可以为不在网格第一列或第一行的每个复选框设置 ::before
和 ::after
伪元素的样式,以便它们分别向左或向上移动,默认情况下隐藏它们。
/* 除第一列外的伪元素 */ input:not(:nth-of-type(4n 1))::before { transform: translatex(-85px); } /* 除第一行外的伪元素 */ input:nth-of-type(n 5)::after { transform: translatey(-60px); }
现在是设置复选框处于 :checked
状态时的样式。首先,让我们给它们一个颜色,比如青柠绿背景:
input:checked { background: limegreen; }
一个选中的框应该能够重新设置所有相邻选中框的样式。换句话说,如果我们选择网格中的第 11 个复选框,我们也应该能够设置其上方、下方、左侧和右侧周围框的样式。
这是通过定位正确的伪元素来完成的。我们如何做到这一点?好吧,这取决于网格中列的实际数量。如果在 5×4 网格中选中两个相邻框,则 CSS 如下:
/* 选中框的右边界(如果其右侧的元素已选中)*/ input:not(:nth-of-type(4n)):checked input:checked::before { border-top-right-radius: 0; border-bottom-right-radius: 0; background: limegreen; } /* 选中框的下边界(如果下面的元素已选中)*/ input:nth-last-of-type(n 5):checked * * * input:checked::after { border-bottom-right-radius: 0; border-bottom-left-radius: 0; background: limegreen; } /* 选中框的相邻(右侧)选中框的左边界 */ input:not(:nth-of-type(4n)):checked input:checked input::before { border-top-left-radius: 0; border-bottom-left-radius: 0; background: limegreen; } /* 选中框的相邻(下方)选中框的上边界 */ input:not(:nth-of-type(4n)):checked * * * input:checked input::before { border-top-left-radius: 0; border-top-right-radius: 0; background: limegreen; }
如果你愿意,你可以动态生成上面的代码。但是,对于一个典型的网格(例如图片库),列的数量将很小,并且可能是固定数量的项目,而行可能会不断增加。特别是如果设计用于移动屏幕。这就是为什么这种方法仍然是一种有效的方法。如果由于某种原因你的应用程序恰好具有有限的行和扩展的列,那么考虑将网格旋转成侧面,因为对于一系列项目,CSS Grid 将它们从左到右、从上到下(即逐行)排列。
我们还需要为网格中的最后一个复选框添加样式——它们并非都由伪元素覆盖,因为它们是每个轴中的最后一项。
/* 选中框(最后一列)的左边界 */ input:nth-of-type(4n-1):checked input:checked { border-top-left-radius: 0; border-bottom-left-radius: 0; } /* 选中框(最后一列)的相邻(下方)选中框的上边界 */ input:nth-of-type(4n):checked * * * input:checked { border-top-left-radius: 0; border-top-right-radius: 0; }
这些选择器很棘手!第一个……
input:nth-of-type(4n-1):checked input:checked
……基本上是这样说的:
在倒数第二列中,一个选中的元素紧挨着一个选中的元素。
nth-of-type
的计算方式如下:
<code>4(0) - 1 = 无匹配项 4(1) - 1 = 第 3 个项目 4(2) - 1 = 第 7 个项目 4(3) - 1 = 第 11 个项目 等等。</code>
所以,我们从第三个复选框开始,从那里选择每个第四个复选框。如果该序列中的复选框被选中,那么如果它们也被选中,我们也会设置相邻复选框的样式。
以及这一行:
input:nth-of-type(4n):checked * * * input:checked
是这样说的:
一个元素,前提是它被选中,直接与一个元素相邻,该元素又直接与另一个元素相邻,该元素又直接与另一个元素相邻,而该元素又直接与一个处于选中状态的元素相邻。
这意味着我们正在选择每个第四个被选中的复选框。如果该序列中的复选框被选中,那么如果它也被选中,我们将设置从该复选框开始的下一个第四个复选框的样式。
我们刚才看到的只是设计背后的普遍原则和逻辑。同样,它在你的应用程序中的实用性将取决于网格设计。
我使用了圆角边框,但你可以尝试其他形状,甚至可以尝试背景效果(Temani 为你提供了想法)。既然你知道公式是如何工作的,剩下的完全取决于你的想象力。
这是一个在简单日历中可能的样子:
同样,这只是一个使用静态标记的粗略原型。而且,在日历功能中需要考虑很多辅助功能方面的考虑。
就是这样!很巧妙,对吧?我的意思是,发生的事情没有什么完全“新的”。但它是一个关于在 CSS 中选择事物的好例子。如果我们掌握了更多使用组合器和伪元素的高级选择技术,那么我们的样式能力就可以超越只设置一个项目的样式——正如我们所看到的,我们可以根据另一个元素的状态有条件地设置项目的样式。
以上是在网格容器中有条件造型选定的元素的详细内容。更多信息请关注PHP中文网其他相关文章!