简体   繁体   English

CSS 选择器以排除任何级别的任何父级具有 class 的所有子级

[英]CSS selector to exclude all children where any parent at ANY LEVEL has a class

What什么

I am trying to create a CSS selector which selects all children within a given parent;我正在尝试创建一个 CSS 选择器,它选择给定父级中的所有子级; but excludes them as long as any element on the path has a certain class.但只要路径上的任何元素具有一定的 class,就将它们排除在外。

Context语境

I am creating some materialisation class in Javascript which replaces some elements into their material versions.我正在 Javascript 中创建一些物化 class ,它将一些元素替换为它们的材料版本。 This runs on a top-level app.这在顶级应用程序上运行。 Each user can create their own apps, and I want to be able to say that a certain group of elements should not go through this process.每个用户都可以创建自己的应用程序,我想说某组元素不应该通过这个过程 go。

Example例子

This should be selected:应该选择这个:

<div>
  <input />
</div>

This should not be selected:不应该选择:

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

The main challenge is that this label can be at any place.主要的挑战是这个label可以在任何地方。 Example:例子:

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

Or it could be:或者它可能是:

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

Already tested已经测试过了

I tried a few attempts.我尝试了几次。 The best scenario was:最好的情况是:

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

However, it stills gives some false positives.但是,它仍然会给出一些误报。 I could get more accurate by adding a lot of levels like:我可以通过添加很多级别来获得更准确的信息,例如:

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)

And like that for 20-50 levels (or more?), but that's not very smart.就像 20-50 级(或更多?)一样,但这不是很聪明。

Live version现场版

You can test your selectors by editing cssSelector in Javascript.您可以通过在 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 -->

Note : I already have thought of other ways of solving this like iterating all the children of an element called '.no-material' and add the class 'no-material' to all, but that is resource consuming and I want to solve this from a CSS selector standpoint if possible.注意:我已经想到了解决这个问题的其他方法,比如迭代一个名为“.no-material”的元素的所有子元素,并将 class “no-material”添加到所有元素中,但这是资源消耗,我想解决这个问题如果可能的话,从 CSS 选择器的角度来看。

Thank you谢谢

Find all the elements ( all ), then the elements with no-material on the element or its parent ( no ), then remove those in the second from those in the first to find those that remain ( yes ).找到所有元素( all ),然后是元素或其父元素上no-material的元素( no ),然后从第一个元素中删除第二个元素以找到剩余的元素( yes )。

 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>

In modern browsers, you can use css variables.在现代浏览器中,您可以使用 ZC7A62​​8CBA22E28EB17B5F5C6AE2A266AZ 变量。

Define it at root level, redefine it in your class:在根级别定义它,在 class 中重新定义它:

 :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>

:not(.no-material, .no-material *)

This will select all elements except those that have the class "no-material" or are a children of an element that has the class "no-material"这将 select 所有元素,除了具有 class“无材料”的元素或具有 class“无材料”的元素的子元素

The key is using a space instead of the > selector, see https://stackoverflow.com/a/2636396/10002734 for the differences between them.关键是使用空格而不是>选择器,请参阅https://stackoverflow.com/a/2636396/10002734了解它们之间的差异。

If you want to only select the elements you have marked as "yes" in the example you could also combine this with the :empty pseudo-selector, like so:如果您只想 select 在示例中标记为“是”的元素,您还可以将其与:empty伪选择器结合使用,如下所示:

:not(.no-material, .no-material *):empty

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM