[英]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.在现代浏览器中,您可以使用 ZC7A628CBA22E28EB17B5F5C6AE2A266AZ 变量。
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.