假设您有一个物品列表。例如,水果:香蕉、苹果、橙子、梨、油桃
我们可以将这些逗号 (,) 放入 HTML 中,但让我们看看如何在 CSS 中做到这一点,这将让我们有更多控制权。我们将确保最后一个项目没有逗号。
我最近在一个实际项目中需要这样做,其中一项要求是列表中的任何项目都可以通过 JavaScript 隐藏/显示。无论当前显示哪些项目,逗号都需要正常工作。
我发现一个相当优雅的解决方案是使用 通用兄弟组合器。我们稍后会谈到这一点。让我们从一些示例 HTML 开始。假设您从一个水果列表开始
<ul class="fruits">
<li class="fruit on">Banana</li>
<li class="fruit on">Apple</li>
<li class="fruit on">Orange</li>
<li class="fruit on">Pear</li>
<li class="fruit on">Nectarine</li>
</ul>
以及一些基本 CSS 使它们以列表形式显示
.fruits {
display: flex;
padding-inline-start: 0;
list-style: none;
}
.fruit {
display: none; /* hidden by default */
}
.fruit.on { /* JavaScript-added class to reveal list items */
display: inline-block;
}
现在假设在这个界面中发生了某些事情,例如用户切换控件,过滤掉所有在寒冷气候中生长的水果。现在显示了一组不同的水果,因此 fruit.on
类使用 classList
API 进行操作。
到目前为止,我们的 HTML 和 CSS 将创建一个这样的列表
BananaOrangeNectarine
现在我们可以使用通用兄弟组合器,在任意两个 on
元素之间应用逗号和空格
.fruit.on ~ .fruit.on::before {
content: ', ';
}
不错!
您可能在想:为什么不直接将逗号应用于所有列表项,并使用类似 :last-child
或 :last-of-type
的东西从最后一个列表项中删除逗号呢?这样做的问题是,最后一个子元素可能在任何时候都是“关闭”的。因此,我们真正想要的是最后一个“打开”的项目,这在 CSS 中不容易实现,因为没有类似“最后一个类”的东西可用。因此,可以使用通用兄弟组合器技巧!
在 UI 中,我使用了 max-width
而不是 display
,并在 0
和一个合理的最大值之间切换,这样我就可以使用过渡更自然地将项目推入和推出,让用户更容易看到哪些项目正在添加到列表中或从列表中删除。您也可以将相同的效果添加到伪元素,使其变得非常流畅。
以下是一个演示,包含两个示例,它们都是略微不同的变体。水果示例使用 hidden
类而不是 on
,而蔬菜示例包含动画。这里也使用了 SCSS 进行嵌套
希望这对其他寻找类似方法的人有所帮助!
为什么这么复杂?为什么不使用类似这样的方法
嘿 Vladislav!我也有同样的想法,但这在列表中的最后一项被隐藏时不起作用(display: none)。我构建的特定情况要求所有元素都存在于 DOM 中并使用类来显示或隐藏它们,因此 :last-child 并不总是指 最后一个可见子元素。
遵循您的逻辑,您可以选择所有非隐藏项目并使用 after 选择器,向所有 除最后一个可见子元素以外的所有项目添加逗号。感谢您的建议!
您的变体在 ios 上不起作用……
实际上,Llull,我认为 Vlad 只是错过了我用来隐藏对象的类,我在此处分叉并还原了它们:https://codepen.io/DaveSeidman/pen/vYXVjPM
当最后一个可见项目不是最后一个实际项目时,它仍然会失败。明天我将看看它 :)
当水果因溢出而分成下一行时,逗号会留在顶行,文本在逗号下方。
蔬菜似乎没有发生同样的情况。
捕捉到了!我错过了 flex-wrap。这里有一个包含部分修复的新笔
唯一的问题是逗号附加到第二个元素的开头 (:before) 而不是第一个元素的结尾 (:after),因此逗号会以错误的方式换行。
是的,尤其是在移动设备上。
我想 :nth-child(n of selector) 在这里也会有用(尽管目前仅在 Safari 中支持)。
如果您有两行以上的文本,则不起作用
我不确定我是否看到了问题,您可以提供一个示例吗?
如果您想遵守不同的语法规则,例如牛津逗号,请尝试;
.fruit:last-child::before { content: ', and '; }
因此结果将是;
香蕉、梨、桃子和蓝莓
我认为这可能存在问题,因为最后一个可见水果并不一定是最后一个子元素。
很棒的想法,是的,您可能需要稍微调整一下选择器。它应该只选择最后一个可见项目:
.on
或:not(.hidden)
您还需要阻止它在列表中只剩下一个项目时添加“and”。可能有一种方法可以做到这一点,方法是检查
:first-of-type(.on)
是否与:last-of-type(.on)
不是同一个元素使用伪元素上的 content 属性的一个缺点是,内容通常不可选,如果用户尝试复制粘贴,可能会导致令人困惑的体验。
复制到剪贴板并粘贴为纯文本时的外观(在我的 Android 手机上;我希望在 Windows 上有类似的行为)
随机水果
香蕉
橙子
梨
随机蔬菜
西兰花
胡萝卜
土豆
菠菜
逗号被删除不是理想的,但换行符至少使它可读。
这两个示例都为辅助技术用户创造了糟糕的体验。使用无序列表的示例至少好一点,至少在 VoiceOver 中是这样,因为它会将自身宣布为列表。第一个示例完全跳过逗号,然后第二个示例宣布一个列表并单独读取每个项目,包括将逗号读取为单独的项目。就我个人而言,根据我对 CSS 内容的了解,您应该只将其用于纯粹的装饰目的,因为屏幕阅读器对它的支持并不好。请参见链接:https://accessibleweb.com/question-answer/how-is-css-pseudo-content-treated-by-screen-readers/
感谢您的检查!我还没有在任何屏幕阅读器上测试过,但我过去曾使用过 Vox 和 VoiceOver。也许将逗号在 <ul> 中的“role”属性设置为不同的值会创造更好的体验?
这很有用,但想知道为什么示例使用逗号(可能是实际散文的一部分)而不是其他分隔符,例如竖线或项目符号(这将更明显地作为列表分隔符,并且更有可能成为实际用例)。
问得好,是的,任何分隔符都可以使用!
在我的特定情况下,我有一些项目数组,这些项目数组用于 JavaScript 生成每个项目的 <button> 和 <span>。按钮具有活动状态和正常状态,但需要始终可见,而 span 需要根据其相应的按钮状态显示和隐藏。我本可以使用 JavaScript 在每次操作时生成一个新的逗号分隔字符串,但我认为将它们保留在 DOM 中并切换其 classList 会更加优雅。
使用 CSS 的创造性方法!
与 Sara 的评论一样,我对这种方法的担忧是网页可访问性。对于任何其他用途,除了装饰性内容以外,使用伪内容都被认为是失败,因为需要自定义或关闭样式信息的使用者可能无法读取和理解内容。
这非常有用且简单。谢谢!