我敢肯定您听说过 CSS 网格。考虑到整个前端开发人员社区在过去一年中一直在热议它,很难错过它。
无论您是 Grid 的新手还是已经使用了一段时间,我们应该从 W3C 的文字 中的简短定义开始这篇文章。
网格布局是 CSS 的一种新的布局模型,它具有强大的功能来控制盒子及其内容的大小和位置。与单轴方向的弹性盒子布局不同,网格布局针对二维布局进行了优化:那些在两个维度上都需要对齐内容的布局。
用我自己的话说,CSS 网格是无形的水平线和垂直线的网格。 我们在这些线之间的空间中排列元素以创建所需的布局。一种更轻松、更稳定且更标准化的方式来在网页中结构化内容。
除了方格纸基础之外,CSS 网格还提供了源顺序无关的布局模型的优势:无论网格项目在源代码中放置在何处,它都可以定位到屏幕上的网格中的任何地方,跨越两个轴。这非常重要,不仅是因为当您发现更新 HTML 并在页面上重新排列元素时会很麻烦,而且在您发现某些源代码位置会限制布局时也很重要。
虽然我们总是可以使用其他技术(如translate
、position
或margin
)将元素移动到屏幕上所需的坐标,但与 CSS 网格等真正的布局机制相比,它们在编码和更新响应式设计等情况时都更难。
在这篇文章中,我们将演示如何使用 CSS 网格的源顺序独立性来解决由于源顺序约束而导致的布局问题。具体来说,我们将看看复选框和 CSS 计数器。
使用复选框进行计数
如果您从未使用过 CSS 计数器,请不要担心,这个概念非常简单!我们将计数器设置为在同一 DOM 层级上计算一组元素。该计数器在这些单个元素的 CSS 规则中递增,本质上是对它们进行计数。
以下是如何计算选中和未选中复选框的代码
<input type="checkbox">Checkbox #1<br>
<input type="checkbox">Checkbox #2
<!-- more checkboxes, if we want them -->
<div class="total">
<span class="totalChecked"> Total Checked: </span><br>
<span class="totalUnChecked"> Total Unchecked: </span>
</div>
::root {
counter-reset: checked-sum, unchecked-sum;
}
input[type="checkbox"] {
counter-increment: unchecked-sum;
}
input[type="checkbox"]:checked {
counter-increment: checked-sum;
}
.totalUnChecked::after {
content: counter(unchecked-sum);
}
.totalChecked::after {
content: counter(checked-sum);
}
在上面的代码中,使用 counter-reset
属性在根元素处设置了两个计数器,并使用 counter-increment
在其各自的规则中递增,一个用于选中复选框,另一个用于未选中复选框。然后,使用counter()
将计数器的值显示为两个空<span>
的伪元素的内容。
以下是使用此代码获得的结果的简化版本
查看 CodePen 上 CSS-Tricks 的 CSS 计数器网格 笔记。(@css-tricks)
这很酷。我们可以将其用于待办事项列表、电子邮件收件箱界面、调查表或任何用户切换框并希望看到已选中和未选中多少项的地方。所有这一切都只需使用 CSS!很有用,不是吗?
但是,当我们意识到显示总计数的元素只能在源代码中要计数的所有元素之后出现时,counter()
的有效性就会减弱。这是因为浏览器首先需要有机会计算所有元素,然后才能显示总数。因此,我们不能简单地更改标记以将计数器放置在复选框上方,如下所示
<!-- This will not work! -->
<div class="total">
<span class="totalChecked"> Total Checked: </span><br>
<span class="totalUnChecked"> Total Unchecked: </span>
</div>
<input type="checkbox">Checkbox #1<br>
<input type="checkbox">Checkbox #2
那么,我们如何在布局中将计数器放置在复选框上方?这就是 CSS 网格及其布局渲染能力发挥作用的地方。
添加网格
我们基本上将之前的 HTML 包装在一个新的<div>
元素中,该元素将充当网格容器。
<div class="grid">
<input type=checkbox id="c-1">
<label for="c-1">checkbox #1</label>
<input type=checkbox id="c-2">
<label for="c-2">checkbox #2</label>
<input type=checkbox id="c-3">
<label for="c-3">checkbox #3</label>
<input type=checkbox id="c-4">
<label for="c-4">checkbox #4</label>
<input type=checkbox id="c-5">
<label for="c-5">checkbox #5</label>
<input type=checkbox id="c-6">
<label for="c-6">checkbox #6</label>
<div class=total>
<span class="totalChecked"> Total Checked: </span>
<span class="totalUnChecked"> Total Unchecked: </span>
</div>
</div>
以下是网格的 CSS 代码。
.grid {
display: grid; /* creates the grid */
grid-template-columns: repeat(2, max-content); /* creates two columns on the grid that are sized based on the content they contain */
}
.total {
grid-row: 1; /* places the counters on the first row */
grid-column: 1 / 3; /* ensures the counters span the full grid width, forcing other content below */
}
这是我们得到的结果(带有一些额外的样式)。
查看 CodePen 上 Preethi 的 CSS 计数器网格 笔记。(@rpsthecoder)
看到了吗?计数器现在位于复选框上方!
我们在 CSS 中定义了网格元素上的两列,每列根据其自身内容的大小进行调整。
当我们将元素网格化时,其内容(包括文本)会形成块级,这意味着它们会获得网格级盒子(类似于块级盒子),并自动放置在可用的网格单元格中。
在上面的演示中,计数器占用了第一行中的两个网格单元格,如指定的那样,之后,每个复选框都位于第一列,每个复选框后的文本都位于最后一列。

由于我们没有更改源顺序,因此计数器可以正常工作,我们可以看到选中和未选中复选框的运行总计数位于顶部,就像它们位于底部时一样。功能不受影响!
说实话,有 无数种方式来编写和实现 CSS 网格。您可以使用网格线编号、命名网格区域以及许多其他方法。您对它们的了解越多,它们就越容易使用,也越有用。我们在这里介绍的只是冰山一角,您可能会发现其他方法来创建同样有效(甚至更好)的网格。
我以前不知道 CSS 计数器是件好事!
同样的事情可以用 flexbox 的 order 属性来实现,不需要定义网格布局。
如果您的设计可以用 flexbox 实现,就可以实现同样的事情。但如果您需要网格……
我同意 hannenz 的观点,在这种情况下,flexbox 会更加直接。不过,文章写得很好。
当然,您也可以在不使用 Grid 的情况下使用 Flexbox 的
order
属性完成同样的事情。谢谢您!有趣的例子。
有几个人指出可以使用 flexbox 的
order
来实现这一点,但order
不是无障碍的,应该尽量避免使用。我必须测试一下 Grid 的方法,看看它是否更适合屏幕阅读器。flexbox 和 grid 在内容重新排序方面遵循相同的模型。文档的选项卡顺序和非视觉表示将遵循文档源顺序。 查看规范
我很高兴有人提到了无障碍性。
使用屏幕阅读器的用户会获取您提供的信息。他们理解有一个菜单可以选择,而不是理解它是一个非常基本的计算器。——如果这确实是一个可供选择的项目列表,我认为他们会感谢复选框组末尾的摘要。但他们不会在点击后立即听到变化(使用实时区域来实现这一点)。
顺便说一下:您真的应该使用标签!
总之:2 个项目中有 6 个项目被选中,这是一个有用的信息吗?——我认为我会很感谢这样的摘要,让我知道“哪些”项目被选中。
此外:我希望没有人会想到使用纯 CSS 创建一个小巧的计算器,因为:关注点分离是一个重要的原则。不要使用 CSS 进行计算。JS 是为此而生的!使用 CSS 代替只是一个 hack……
在某些情况下,CSS 计算对于改变某些内容的设计以指示是否达到某个阈值或类似的东西对那些能看到颜色的人是有用的。
在这个例子中,我理解计数器是一个简单的易用性增强功能,应该可以工作——大多数屏幕阅读器会读出
:after
和:before
的内容。但它还是像一个 hack——至少是一个诱人的、美丽的、直观的 hack ;-)使用 css 对元素进行排序的重点是保持结构的可访问性,对吗?
我对网格的使用并不感到印象深刻(我们有足够的时间对 CSS 网格感到印象深刻:D),但对计数器的使用非常有创意!很好!