在 CSS 中,我如何 select 元素*不是*具有符合可识别模式的 class 容器元素的后代?

In CSS, how may I select elements which are *not* the descendants of a container element with a class conforming to a recognisable pattern?

假设下面的HTML和CSS已经设置好

在已经写好的CSS下面加什么CSS规则可以让红色段落显示为红色?

body,
div {
  display: flex;
  flex-wrap: wrap;
}

p {
  margin: 6px;
}

.one-filter-one p,
p[class^="one-filter-one"] {
  color: blue;
}

.two-filter-two p,
p[class^="two-filter-two"] {
  color: green;
}

.four-filter-four p,
p[class^="four-filter-four"] {
  color: orange;
}
<p class="another-class">This is red.</p>
<p>This is red.</p>

<div class="one-filter-one">
  <p>This is blue.</p>
  <p class="one-filter-one--paragraph">This is blue.</p>
</div>

<p class="two-filter-two">This is green.</p> 

<p>This is red.</p> 
<p class="another-class-two">This is red.</p>

<div class="three-filter-three">
  <p>This is unstyled (black).</p>
  <div><p>This is unstyled (black) too.</p></div> 
</div>

<div class="four-filter-four">
  <p class="four-filter-four--sentence">This is orange.</p>
</div>
  
<p class="five-filter-five">This is also unstyled (black).</p>

<div class="another-class-three">
  <p>This is red.</p>
  <p class="another-class-four">This is red.</p>
</div>


我最好的猜测是使用 :not() 伪 class.

但我并不完全相信这是正确的方法,主要是因为我不确定 :not() 是否可以处理这种情况。

我的解决方案尝试,使用 :not():

body,
div {
  display: flex;
  flex-wrap: wrap;
}

p {
  margin: 6px;
}

.one-filter-one p,
p[class^="one-filter-one"] {
  color: blue;
}

.two-filter-two p,
p[class^="two-filter-two"] {
  color: green;
}

.four-filter-four p,
p[class^="four-filter-four"] {
  color: orange;
}

p:not([class*="-filter-"]) {
  color: red;
}
<p class="another-class">This is red.</p>
<p>This is red.</p>

<div class="one-filter-one">
  <p>This is blue.</p>
  <p class="one-filter-one--paragraph">This is blue.</p>
</div>

<p class="two-filter-two">This is green.</p> 

<p>This is red.</p> 
<p class="another-class-two">This is red.</p>

<div class="three-filter-three">
  <p>This is unstyled (black).</p>
  <div><p>This is unstyled (black) too.</p></div> 
</div>

<div class="four-filter-four">
  <p class="four-filter-four--sentence">This is orange.</p> </div>
  
<p class="five-filter-five">This is also unstyled (black).</p>

<div class="another-class-three">
  <p>This is red.</p>
  <p class="another-class-four">This is red.</p>
</div>

显然不是这个,因为我没有正确选择:

不是 [class*="-filter-"] 后代 元素。

但我完全不清楚该怎么做。

鉴于 CSS 的当代能力,有什么办法可以做到这一点,或者我是否希望在 2020 年实现不可能的目标?


备注:

尽管在 2020 年,伪 class :not() 已经存在了十年的大部分时间,但我一直倾向于避免使用它。我唯一知道的是 :not() 伪 class 函数只能采用简单(即非复合)选择器。


已添加:

根据 @G-Cyrillus 的绝妙建议(在下面的评论中),我提出了以下建议:

body > p:not([id*="-filter-"]):not([class*="-filter-"]),
body > :not([class*="-filter-"]) > p:not([id*="-filter-"]):not([class*="-filter-"]),
body > :not([class*="-filter-"]) > :not([class*="-filter-"]) > p:not([id*="-filter-"]):not([class*="-filter-"]),
body > :not([class*="-filter-"]) > :not([class*="-filter-"]) > :not([class*="-filter-"]) > p:not([id*="-filter-"]):not([class*="-filter-"]),
body > :not([class*="-filter-"]) > :not([class*="-filter-"]) > :not([class*="-filter-"]) > :not([class*="-filter-"]) > p:not([id*="-filter-"]):not([class*="-filter-"]) {
  color: red;
}

从好的方面来说,这 确实 有效。 (所以,比我以前拥有的任何东西都要好得多)。

负面:

这是一次教育活动。

它教会我的最重要的事情是,鉴于 :not() 不能接受 复合选择器 ,处理后续 远非直接应用 :not().

后的嵌套标记级别

鉴于以下情况:

.filter-1 {
  color: red;
}

:not([class^="filter-"]) p {
  color: blue;
}
<div>
  <div>
    <p>Test.</p>
  </div>
</div>

<div class="filter-1">
  <div>
    <p>Test.</p>
  </div>
</div>

第二个<p>仍然出现blue

为什么?因为即使它的 grandparent 有 class .filter-1,它的直接 parent 没有 ...这足以满足CSS规则中p之前的任何后代选择器(即[SPACE]):

:not([class^="filter-"]) p

解决此问题的唯一方法是将规则替换为:

:not([class^="filter-"]) > * > p

现在可以使用了:

.filter-1 {
  color: red;
}

:not([class^="filter-"]) > * > p {
  color: blue;
}
<div>
  <div>
    <p>Test.</p>
  </div>
</div>

<div class="filter-1">
  <div>
    <p>Test.</p>
  </div>
</div>

但是...

CSS 规则现在 紧密绑定 到 HTML 结构,上面修改后的 CSS 规则现在不适用于:

<div class="filter-2">
  <p>Test.</p>
</div>

参见:

.filter-1 {
  color: red;
}

:not([class^="filter-"]) > * > p {
  color: blue;
}
<div>
  <div>
    <p>Test.</p>
  </div>
</div>

<div class="filter-1">
  <div>
    <p>Test.</p>
  </div>
</div>

<div class="filter-2">
  <p>Test.</p>
</div>

相反,我们现在需要使用 两个规则:

:not([class^="filter-"]) > p,
:not([class^="filter-"]) > * > p

得出以下结论:

We can only use :not() to exclude descendants when we also explicitly describe the HTML structure in the CSS.

我现在更清楚地理解了@G-Cyrillus的意思:

You need to mind the structure too


后续步骤:

在我的 CSS 中描述无限数量的潜在后代结构显然是不切实际的,所以我:

1) 重新配置了我的体系结构以允许在其他地方描述更复杂的后代关系

2) 将我的排除查询优化为:

body > :not([id^="filter-"]):not([class^="filter-"])

再次感谢,@G-Cyrillus - 由于您在评论部分的大力帮助,我才做到了这一点。