【问题标题】:CSS Selector "(A or B) and C"?CSS选择器“(A或B)和C”?
【发布时间】:2024-05-21 08:55:01
【问题描述】:

这应该很简单,但我无法找到它的搜索词。
假设我有这个:

<div class="a c">Foo</div>
<div class="b c">Bar</div>

在 CSS 中,如何创建一个选择器来匹配匹配“(.a 或 .b)和 .c”的内容?

我知道我可以这样做:

.a.c,.b.c {
  /* CSS stuff */
}

但是,假设我必须经常做这种逻辑,有多种逻辑组合,有没有更好的语法?

【问题讨论】:

    标签: html css css-selectors


    【解决方案1】:

    有更好的语法吗?

    没有。 CSS 的 or 运算符 (,) 不允许分组。它本质上是选择器中优先级最低的逻辑运算符,因此您必须使用.a.c,.b.c

    【讨论】:

      【解决方案2】:

      还没有,但是有一个实验性的:is()(以前的:matches())伪类选择器可以做到这一点:

      :is.a .b) .c {
        /* stuff goes here */
      }
      

      您可以在herehere 找到更多信息。目前,大多数浏览器都支持其初始版本:any(),其工作方式相同,但将被:is() 取代。在到处使用它之前,我们只需要再等一会儿(我肯定会的)。

      【讨论】:

      • 责怪 IE 没有实现他们根本没想到的东西,而且一开始就没有在任何草案中,这是不合理的。 :-moz-any():-webkit-any() 早在 Mozilla 为 Selectors 4 推荐它之前就出现了(导致它目前的化身为 :matches())。
      • 期望任何供应商从不稳定的草案中实现功能同样不合理,而不管草案已经提供了多长时间(这是因为 Selectors 4 仍然不稳定且很大程度上未实现) FPWD 后三年多)。
      • @BoltClock,他们整整十年都将 IE6 归咎于 2001 年不存在的事情。人们只是想责怪某人。
      • 关于实验性的一个词是,除非正式实施,否则您不想开始依赖它们。虽然它看起来像是一个很好的解决方案 - 它可能会消除个人阻止我在我的项目中实施它的可能性。即使跟踪一个实验性的伪类也不会让我感到安全。很可能它将在项目中的多个地方使用,以防万一,如果您有多个使用它的地方 - 您需要以某种方式跟踪所有内容。你当然可以有后备,但仍然可以成功,但这听起来并不干净
      • 不再是实验性的。 :is() 自 2021 年 2 月 (MDN) 以来已在所有主要浏览器中实现 - 尽管将其用于 Web 应用程序可能还为时过早(没有后备)。
      【解决方案3】:

      对于阅读本文的人 >= 2021:

      我发现使用 :is() 选择器成功了:

      *:is(.a, .b).c{...}
      

      【讨论】:

      • 谢谢。我想知道9年前我问这个问题时“:is()”选择器是否存在?
      • 我对此表示怀疑! @Josh --> 我留下了这个答案,因为这篇文章是我在谷歌上搜索如何在 CSS 选择器中组合类时排名第一的结果。对于目前正在观看的人来说,这个答案很有帮助——尽管之前的答案可能更多地显示了技术进化的产物。
      • @Josh is() 取代了 Metalcoder 2014 年的回答中的 :matches()。有关更多信息,请参阅 developer.mozilla.org/en-US/docs/Web/CSS/:is
      • 好奇我做错了什么?这个:*:is(.foo, .bar) ~ .baz { margin-top: 10px; } ...编译成这个:*:is(.foo):is(.bar) ~ .baz { margin-top: -10px; } ...但是编译抛出:“:is(.foo)”不是一个有效的伪类。 ":is(.bar)" 不是一个有效的伪类。
      【解决方案4】:

      如果你有这个:

      <div class="a x">Foo</div>
      <div class="b x">Bar</div>
      <div class="c x">Baz</div>
      

      而您只想选择具有.x 和(.a.b)的元素,您可以这样写:

      .x:not(.c) { ... }
      

      但这只有在你有三个“子类”并且你想选择其中两个时才方便。

      只选择一个子类(例如.a):.a.x

      选择两个子类(例如.a.b):.x:not(.c)

      选择所有三个子类:.x

      【讨论】:

      • a or b or c or d 形式的任何逻辑子句都与not(not(a) and not(b) and not(c) and not(d)) 相同,因此“或”实际上只是一个便利函数。理论上,在所有的情况下应该可以不用它。在 OP 的情况下 (.a or .b) and .c -> :not(:not(.a):not(.b)).c
      • @MaxMurphy 你测试过这个吗?
      • 今天早上五点,是的!我有 js 吐出一阶逻辑,在叶子上有选择器,给出诸如:not(:not([data-status="ACT"]):not([data-status="ISS"]):not([data-status="COR"]))[data-month="08"] 之类的结果。该代码还不够干净,无法供公众阅读,否则我会发布它。我在 chrome、safari 和低端安卓手机上进行了测试。
      • @MaxMurphy 你的观点很好,但我认为你引用了一个相当折磨人的“便利功能”定义。数字计算机可以做的任何事情都可以分解为与非门,但我不会将软件工程的其余部分称为“一堆便利功能”。当结构可以组合时,程度的差异很快就会变成事实上的种类差异。
      • @MaxMurphy 我很难确定你只是在开玩笑。 :( 否定 CSS 伪类 :not(X) 是一个以 简单选择器 X 作为参数的函数式表示法。它匹配参数未表示的元素。 X 不得包含另一个否定选择器(来自Mozilla docs,强调我的)
      【解决方案5】:

      没有。标准 CSS 不提供您正在寻找的那种东西。

      但是,您可能需要查看 LESSSASS

      这两个项目旨在通过引入附加功能(包括变量、嵌套规则和其他增强功能)来扩展默认 CSS 语法。

      它们允许您编写更加结构化的 CSS 代码,并且几乎可以肯定它们中的任何一个都可以解决您的特定用例。

      当然,没有一个浏览器支持它们的扩展语法(特别是因为这两个项目都有不同的语法和特性),但它们所做的是提供一个“编译器”,它将你的 LESS 或 SASS 代码转换为标准 CSS,它然后,您可以在您的站点上进行部署。

      【讨论】:

      • 那个时候我还不如直接用PHP打印"Content-type: text/css"