CSS选择器用于排除ANY LEVEL中任何父级具有类的所有子级

时间:2017-06-12 08:18:41

标签: javascript html css css3 css-selectors

什么

我正在尝试创建一个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来测试您的选择器。

&#13;
&#13;
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'));
&#13;
<!-- 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 -->
&#13;
&#13;
&#13;

注意:我已经想到了解决这个问题的其他方法,例如迭代一个名为&#39; .no-material&#39;的元素的所有子元素。并添加课程&#39; no-material&#39;对所有人而言,这是消耗资源的,如果可能的话,我想从CSS选择器的角度来解决这个问题。

谢谢

2 个答案:

答案 0 :(得分:1)

找到所有元素(all),然后在元素或其父元素(no-material)上找到no的元素,然后将第二个元素从第一个元素中删除找到那些剩下的(yes)。

&#13;
&#13;
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));
&#13;
<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>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

在现代浏览器中,您可以使用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>