Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Description of :not() selector #16975

Closed
glorious1 opened this issue Jun 4, 2022 · 13 comments · Fixed by #18730
Closed

Description of :not() selector #16975

glorious1 opened this issue Jun 4, 2022 · 13 comments · Fixed by #18730
Labels
Content:CSS Cascading Style Sheets docs

Comments

@glorious1
Copy link

glorious1 commented Jun 4, 2022

MDN URL

https://developer.mozilla.org/en-US/docs/Web/CSS/:not

What specific section or headline is this issue about?

Description, 6th bullet

What information was incorrect, unhelpful, or incomplete?

This is confusing and may be an error. I think it might be correct if "ancestors" were changed to "children" (or "descendants"?), as in:

"This selector only applies to one element; you cannot use it to exclude all ancestors children. For instance, body :not(table) a will still apply to links inside a <table>, since <tr> will match with the :not() part of the selector."

What did you expect to see?

Previous field says it all.

Do you have any supporting links, references, or citations?

No response

Do you have anything more you want to share?

No response

MDN metadata

Page report details
@github-actions github-actions bot added Content:CSS Cascading Style Sheets docs needs triage Triage needed by staff and/or partners. Automatically applied when an issue is opened. labels Jun 4, 2022
@sideshowbarker sideshowbarker added help wanted If you know something about this topic, we would love your help! effort: small This task is a small effort. and removed needs triage Triage needed by staff and/or partners. Automatically applied when an issue is opened. labels Jun 5, 2022
siddhardha123 added a commit to siddhardha123/content that referenced this issue Jun 15, 2022
@edbaafi
Copy link

edbaafi commented Jun 15, 2022

Looking at this issue while filing this one, it seems this bullet point was actually a hold over from when :not only supported simple selectors (Selectors Level 3). With the Selectors Level 4 version of :not (available in all major browsers) you can in fact use :not to exclude all children. See below where :not(div > *) is used to exclude all children of divs:

<style>
  p:not(div > *){
    color:red;
  }
</style>
<p>red</p>
<div><p>black</p></div>

I think this bullet point should actually be removed as it might be futile to continue editing it to try to make it correct when the initial premise is no longer true.

@estelle
Copy link
Member

estelle commented Jun 15, 2022

This is a tricky one. Selectors are read right to left, so your selecting all links and hoping to exclude links that have a specific "ancestor" in this case

edbaafi is right in that it should either be removed or explained in a less confusing way, but children is not it, I don't think.

@edbaafi
Copy link

edbaafi commented Jun 15, 2022

yes children (and from the other direction - parent) is not it.. especially because excluding elements with specific parents was possible before Selectors level 4 as a:not( tr > * ) is essentially equivalent to :not( tr ) > a which was possible in level 3. IMO there are no unusual effects and outcomes (what the description in question claims to address) regarding :not(...) only applying to one element. Simple selectors always apply to only one element, even if the element that you're describing is the parent or ancestor of the final selected element (to the left of a child or descendant combinator).

IMO what the original bullet was trying to highlight was that:

  1. Excluding an element based on having an ancestor at some unspecified level was not possible before (Selectors level 3)
  2. Wishful thinking and/or faulty logic might have one assume that :not(.ancestor) .descendant could accomplish this.

Now that this is possible with Selectors level 4, if this bullet point is to stay (to remedy the faulty logic aspect), perhaps something like this is clearer:

Be careful when trying to exclude an element with one specific ancestor (with descendant combinators). Consider the markup<ul><li><a href="">link</a></li></ul>. The selector body :not(ul) a means "select an <a> element with an ancestor that is not a <ul> and a further ancestor that is <body>". This would fail to exclude the <a> element because the <li> element is an ancestor that is "not a <ul>" thus fulfilling the :not() part of the selector. Use a:not(ul *) or a:not(ul a) in this case

@glorious1
Copy link
Author

perhaps something like this is clearer:

Be careful when trying to exclude an element with one specific ancestor (with descendant combinators). Consider the markup<ul><li><a href="">link</a></li></ul>. The selector body :not(ul) a means "select an <a> element with an ancestor that is not a <ul> and a further ancestor that is <body>". This would fail to exclude the <a> element because the <li> element is an ancestor that is "not a <ul>" thus fulfilling the :not() part of the selector. Use a:not(ul *) or a:not(ul a) in this case

This is tricky stuff, but I understand it and it makes sense.

@estelle
Copy link
Member

estelle commented Jun 15, 2022

that would work.

I think removing all of

This selector only applies to one element; you cannot use it to exclude all ancestors. For instance, body :not(table) a will still apply to links inside a <table>, since <tr> will match with the :not() part of the selector.

and then adding the above after the unordered list, not within it, since it starts with a "be careful" statement.

@deepug9787
Copy link
Contributor

deepug9787 commented Jul 24, 2022

How about we rewrite it to something like this:

The :not() pseudo-class may not work as expected when used with descendant combinators. For instance, if you do body :not(table) a, instead of excluding all the links that are the direct or indirect children of table like you would expect, it excludes only the links that are direct children of table. That means any links you may have inside a tr or td will still be selected.

Reads more clearer to me.

@sideshowbarker
Copy link
Collaborator

How about we rewrite it to something like this:

The :not() pseudo-class may not work as expected when used with descendant combinators. For instance, if you do body :not(table) a, instead of excluding all the links that are the direct or indirect children of table like you would expect, it excludes only the links that are direct children of table. That means any links you may have inside a tr or td will still be selected.

Reads more clearer to me.

Me too. Would be great if you could put together a PR with that change.

@edbaafi
Copy link

edbaafi commented Jul 24, 2022

@deepug9787 @sideshowbarker Sorry but this is not correct. Please revert this change and reopen this issue.

if you do body :not(table) a, instead of excluding all the links that are the direct or indirect children of table like you would expect, it excludes only the links that are direct children of table

In the example you listed, there is nothing that causes this selector to exclude only the links that are direct children of table. The issue that seems to be tripping people up (including how you explained your example) is that :not() never really "excludes" anything from the final resulting matched elements. :not() is still a selector and its job is to "select" not "exclude" elements. So in your example, the thing that seems to be confusing to people is that any element that is not a <table> will satisfy the :not(table) part of the selector. So as long as there is any non-table (that is also a descendant of <body>) that is an ancestor of the <a> then the <a> element will be selected (the usual - not unusual - result of a descendant combinator). Thus, while perhaps impractical since browsers (at least chrome) will not allow an <a> as a direct child of a <table> element (chrome reparents the <a> if one attempts to do this), even if an <a> was a direct child of a <table> it would be selected (not excluded) as long as there is some non-table ancestor of the <a> that also has an ancestor of <body>.

A counterexample showing your explanation/logic is incorrect (changing <table> for class="table" so you can actually test this) is:

<head>
    <style>
        body :not(.table) a{
            color: red;
        }
    </style>
</head>
<body>
    <main>
        <div class="table">
            <a href="#">not "excluded" so this will be red</a>
        </div>
    </main>
</body>

Thus we can't say this selector excludes the links that are direct children of table. That definitely does not help to clarify any confusion as it is simply not true. Please see my thoughts above on how this bullet point seemed to have been related to limitations of Selector Level 3 which did not allow body :not(.table a) which now works in all major browsers. The fact this wasn't previously supported was the only thing that was "unusual" which is what this section was about. If we think developers/designers will still be confused about how saying something is:

not an element that is a descendant of an element with a specific selector

which is what :not(.table a) says - is different from saying something has:

any ancestor that does not match a specific selector

which is what :not(.table) a says - then we should at least make sure our examples/explanation are correct and include the correct (i.e. Selector Level 4) way of doing it.

I can provide a correct example/explanation but need to know what we are trying to accomplish with this bullet point and if we think this is still relevant given Selector Level 4 removed the initial limitation.

@edbaafi
Copy link

edbaafi commented Jul 24, 2022

@estelle see incorrect logic/explanation in merged PR ^

sideshowbarker added a commit that referenced this issue Jul 25, 2022
@sideshowbarker sideshowbarker removed effort: small This task is a small effort. help wanted If you know something about this topic, we would love your help! labels Jul 25, 2022
@github-actions github-actions bot added the needs triage Triage needed by staff and/or partners. Automatically applied when an issue is opened. label Jul 25, 2022
@sideshowbarker sideshowbarker removed the needs triage Triage needed by staff and/or partners. Automatically applied when an issue is opened. label Jul 25, 2022
@deepug9787
Copy link
Contributor

I think I moved a little too quickly on this one. Seeing that there was already a discussion going on around this issue, I should've waited for everyone's feedback before I issued the PR. My apologies.

@sideshowbarker
Copy link
Collaborator

I think I moved a little too quickly on this one. Seeing that there was already a discussion going on around this issue, I should've waited for everyone's feedback before I issued the PR. My apologies.

No worries — it’s under version control and nothing’s destructive, and it didn’t break a build or somethng. If anything, it helped make clear we all care about getting it right

@sideshowbarker
Copy link
Collaborator

I can provide a correct example/explanation but need to know what we are trying to accomplish with this bullet point and if we think this is still relevant given Selector Level 4 removed the initial limitation.

That part I can’t answer because it’s not clear to me either what it’s currently intending to accomplish

@Josh-Cena
Copy link
Member

We can consider this done via #18748?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Content:CSS Cascading Style Sheets docs
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants