21

Let's say I have :

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Test for :not</title>
        <link rel="stylesheet" type="text/css" href="Test.css" />
    </head>
    <body>
        <div class="a">
            <p class="para">This line should be green.</p>
        </div>
        <div class="a">
            <p class="para">This line should also be green.</p>
            <div class="ds">
                <p class="para">This is another line that should be yellow</p>
            </div>
        </div>
    </body>
</html>

I want to select all the elements with class="para" but exclude those that are descendants of those elements that have a class="ds". I have this CSS:

.ds { color: grey; border-style:solid; border-width:5px;}
                
.para {color:yellow;}
                
.para:not(.ds .para) {color:green; border-style:solid; border-width:5px;} //not working

So I assume I can only have simple selectors as part of :not(S), I can't have :not (X Y). I am running in both Chrome (18.0.1025.162 m) and Firefox (10). Any ideas?

Please note: That the query is part of a bigger issue, I have some code (in gwt) that is selecting a list of elements (e.g. with class="para") from the DOM. However, I have found a bug that requires the exclusion of elements that are descendants of a particular set of elements (e.g those with a class="ds").

Ole Pannier
  • 3,208
  • 9
  • 22
  • 33
Asim
  • 869
  • 1
  • 10
  • 17
  • Can you be more specific? What do you mean "no control over the code"? What *do* you have control over? – Jon Apr 19 '12 at 12:10
  • 3
    It means that i am using a 3rd party library using gwt, all i am looking for is a style that i can apply to this specific call. – Asim Apr 19 '12 at 12:26
  • Ummm... call? What call? – Jon Apr 19 '12 at 12:33
  • 4
    Its irrelevant at this point, i think my question is clear enough – Asim Apr 19 '12 at 12:37
  • 4
    I have added a new note to describe why i need to do this, even though i think it is irrelevant, it is a shame that i came here to ask help for an issue that i have but instead my question is marked down simply because it cannot be answered. – Asim Apr 19 '12 at 13:04
  • Your question was marked down (not by me) because frankly, it's been badly asked. IMHO part of the reason is that you have ran foul of the [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) and you are not responsive to dialogue (at least with me). Just my opinion, cheers. – Jon Apr 19 '12 at 13:15
  • 5
    How was it badly asked, i wish i was told rather than being marked down. And with all due respect i modified my question several times and also to explain why i was asking this question. I asked a question but was given with the typical why does it need to be done this way response. Believe me if i could i wouldn't do it this way but sometimes we have to and you should know this. – Asim Apr 19 '12 at 13:55

3 Answers3

17

The spec says that you can have any simple selector inside :not, where

A simple selector is either a type selector, universal selector, attribute selector, class selector, ID selector, or pseudo-class.

So yes, you can't have a descendant selector :not(X Y). There is also the problem that when using the descendant selector you can only express positives ("when X's ancestors include a Y") and not negatives ("when X's ancestors do not include a Y");

The most practical solution would be to reverse the CSS logic so that the negative you want to express becomes a positive:

.ds .para { background:gold; }
.para { background: green }

See it in action.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • Please see the note i added to the original question. – Asim Apr 19 '12 at 12:07
  • In CSS 4, the :not pseudo class now accepts complex selectors, and that part of the spec is broadly supported - https://caniuse.com/?search=%3Anot() - so this answer is out of date as of 2023. – Eamon Nerbonne May 13 '23 at 14:26
4

Elements with class "para" excluding those that are immediate children of elements with class "ds" is:

*:not(.ds) > .para
Alexander Pavlov
  • 31,598
  • 5
  • 67
  • 93
  • 3
    Won't work as it stands. Any other element in its hierarchy will match it. It'd only work for `>`. – Chris Morgan Apr 19 '12 at 11:54
  • 1
    @ChrisMorgan You are correct, will work only for the immediate children. – Alexander Pavlov Apr 19 '12 at 12:00
  • @AlexanderPavlov: I mean, it'd only work if you changed the general descendant selector to the direct descendant selector (`>`). Otherwise e.g. `` will match `*:not(.ds)` and then it'll select all `.para` descendants of it. – Chris Morgan Apr 19 '12 at 12:01
  • 1
    It only works for direct descendants which is not what i am looking for – Asim Apr 19 '12 at 12:23
1

I think you may be approaching it in the wrong way. Normal .para matches are green, and ones in .ds are yellow. To be sure, with the way you have it you would then need to remove the border once more, but that's not a problem.

.ds { color: grey; border-style:solid; border-width:5px;}

.para {color:green; border-style:solid; border-width:5px;}

.ds .para {color:yellow; border-style: none; }

This fits with what I see as the natural way of interpreting the formatting.

Chris Morgan
  • 86,207
  • 24
  • 208
  • 215