【问题标题】:CSS selector to exclude all children where any parent at ANY LEVEL has a classCSS选择器排除任何级别的任何父级具有类的所有子级
【发布时间】:2017-06-12 21:52:39
【问题描述】:

什么

我正在尝试创建一个 CSS 选择器,它可以选择给定父级中的所有子级;但只要路径上的任何元素都有特定的类,就会排除它们。

上下文

我正在用 Javascript 创建一些物化类,它将一些元素替换为它们的材料版本。这在顶级应用程序上运行。每个用户都可以创建自己的应用程序,我想说的是,某组元素不应该经历这个过程。

示例

应该选择这个:

<div>
  <input />
</div>

这不应该被选中:

<div class="no-material">
  <input />
</div>

主要的挑战是这个标签可以在任何地方。示例:

  <main>
    <section class="no-material">
      <form>
        <fieldset>
          <input />
        </fieldset>
      </form>
    </section>
  </main>

也可能是:

  <main>
    <section>
      <form class="no-material">
        <fieldset>
          <input />
        </fieldset>
      </form>
    </section>
  </main>

已经测试过

我尝试了几次。最好的情况是:

div:not(.no-material) > input:not(.no-material), div:not(.no-material) *:not(.no-material) input:not(.no-material)

但是,它仍然会给出一些误报。我可以通过添加很多级别来获得更准确的信息,例如:

div:not(.no-material) > input:not(.no-material),
div:not(.no-material) > *:not(.no-material) > input:not(.no-material),
div:not(.no-material) > *:not(.no-material) > *:not(.no-material) > input:not(.no-material)

像这样 20-50 级(或更多?),但这不是很聪明。

现场版

您可以通过在 Javascript 中编辑 cssSelector 来测试您的选择器。

let cssSelector = [
  // Independent selectors
  'div:not(.no-material) > input:not(.no-material)',
  'div:not(.no-material) *:not(.no-material) input:not(.no-material)'
].join(',');

// This will get elements and run their names. We should get yes1-5, but not no1-5.
let inputs = document.querySelectorAll(cssSelector);
for (let input of inputs) console.log(input.getAttribute('name'));
<!-- Do not edit HTML, just the CSS selector -->

<main style="display: none;">

  <!-- Not selectable -->
  <div class="no-material">
    <input name="no-1">
  </div>

  <div>
    <input name="no-2" class="no-material">
  </div>

  <div>
    <label class="no-material">
      <input name="no-3">
    </label>
  </div>

  <div>
    <label class="no-material">
      <span>
        <input name="no-4">
      </span>
    </label>
  </div>

  <div>
    <label>
      <span class="no-material">
        <input name="no-5">
      </span>
    </label>
  </div>

  <!-- Selectable -->
  <div>
    <input name="yes-1">
  </div>

  <div>
    <input name="yes-2">
  </div>

  <div>
    <label>
      <input name="yes-3">
    </label>
  </div>

  <div>
    <label>
      <span>
        <input name="yes-4">
      </span>
    </label>
  </div>

  <div>
    <label>
      <span>
        <input name="yes-5">
      </span>
    </label>
  </div>

</main>
<!-- Do not edit HTML, just the CSS selector -->

注意:我已经想到了解决这个问题的其他方法,比如迭代一个名为“.no-material”的元素的所有子元素并将类“no-material”添加到所有元素中,但是这是资源消耗,如果可能的话,我想从 CSS 选择器的角度来解决这个问题。

谢谢

【问题讨论】:

  • 无论如何,如果 CSS 选择过程没有任何索引(不确定其内部结构),您最终将以一种或另一种形式迭代所有元素。您可以通过 $("[class]") 选择器(这是一个文字)迭代所有带有类的项目,然后如果它们有一个带有您要过滤的类的父项。
  • 对于初学者来说,当你想匹配任何级别的孩子时,不要使用&gt;(直接孩子)。
  • 这是已解决问题的副本:全局选择器与 :not(.class) 结合似乎不起作用stackoverflow.com/a/44497536/7973110
  • 他们在 1 小时前问过,我在 3 小时前问过 :) 但是,是的,这似乎是同一个问题,以至于我看到相同的 span.no-material 里面有一个输入(这是一个结构很差)。 @JenniferGoncalves
  • @fvbuendia 对此表示赞同,并在另一个问题中对您的问题表示赞赏。

标签: javascript html css css-selectors


【解决方案1】:

找到所有元素(all),然后是元素或其父元素上带有no-material的元素(no),然后从第一个元素中删除第二个元素以找到剩余的元素(@ 987654324@).

const difference = (a, b) => a.filter(elt => b.indexOf(elt) === -1);
  
const all = document.querySelectorAll("input");
const no = document.querySelectorAll(".no-material input, input.no-material");

const yes = difference([...all], [...no]);

console.log(yes.map(elt => elt.name));
<main style="display: none;">

  <!-- Not selectable -->
  <div class="no-material">
    <input name="no-1">
  </div>

  <div>
    <input name="no-2" class="no-material">
  </div>

  <div>
    <label class="no-material">
      <input name="no-3">
    </label>
  </div>

  <div>
    <label class="no-material">
      <span>
        <input name="no-4">
      </span>
    </label>
  </div>

  <div>
    <label>
      <span class="no-material">
        <input name="no-5">
      </span>
    </label>
  </div>

  <!-- Selectable -->
  <div>
    <input name="yes-1">
  </div>

  <div>
    <input name="yes-2">
  </div>

  <div>
    <label>
      <input name="yes-3">
    </label>
  </div>

  <div>
    <label>
      <span>
        <input name="yes-4">
      </span>
    </label>
  </div>

  <div>
    <label>
      <span>
        <input name="yes-5">
      </span>
    </label>
  </div>

</main>

【讨论】:

  • 这实际上是针对 Javascript 的;但我想解决它一个 querySelectorAll 级别,是的。我看不到您的案例如何解决问题。我正在尝试添加所有输入,除了父母(在任何级别)具有 .no-material 的输入,这是选择其父母具有 .no-material 的输入,这似乎微不足道,但恰恰相反,这很难: )
  • 由于没有更好的答案,我将此标记为已回答。我使用 Set() 和迭代器采用了类似的方法,但背后的概念相同。
【解决方案2】:

在现代浏览器中,您可以使用 css 变量。

在根级别定义它,在你的类中重新定义它:

:root {
    --mycolor: lightblue;
}

.container {
    --mycolor: lightgreen;
}

.test {
    background-color: var(--mycolor);
}
<div class="test">BASE</div>

<div class="container">
    <div class="test">BASE</div>
</div>

【讨论】:

  • 谢谢。这很好,但在这里不能达到目的。 CSS 选择器在 Javascript 中用于将某些类和行为应用于元素。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-22
  • 2016-04-19
  • 1970-01-01
  • 1970-01-01
  • 2011-04-28
相关资源
最近更新 更多