10

I don't understand why the following code has not desired behaviour:

    .toggle {
      color: red;
    }
    
    :not(.list) .toggle {
      font-weight:bold;
    }
  <div class="container">
      <a href="#!" class="toggle">Toggle</a>
      <ul class="list">
        <li><a href="#!">Link 1</a></li>
        <li>
          <div class="container">
            <a href="#!" class="toggle">SubToggle</a>
            <ul class="list">
              <li><a href="#!">SubLink 1</a></li>
              <li>
                <a href="#!">SubLink 2</a>
              </li>
              <li><a href="#!">SubLink 3</a></li>
            </ul>
          </div>
        </li>
        <li><a href="#!">Link 3</a></li>
      </ul>
    </div>

I thought that using :not() would result in applying "bold" only to main "Toggle" link but instead it applis "bold" to all of red ones. Why?

Please, note that this code is nested with same class names, I don't want to target specific levels with different css classes, I would like to target elements only with descendant selectors and other operators

Here is present also a jsFiddle to directly try.

Zeev Katz
  • 2,273
  • 2
  • 16
  • 42
Luca Detomi
  • 5,564
  • 7
  • 52
  • 77
  • you try to do this? https://jsfiddle.net/zeevkatz/1yy72grr/1/ – Zeev Katz Oct 24 '16 at 09:14
  • @LucaDetomi: This is a known behavior. It happens because the second toggle's (the Sub toggle) immediate parent also doesn't have `class='list'` so that also applies the `:not(.list) .toggle`. – Harry Oct 24 '16 at 09:20
  • @Harry Yes, it's true, but your description would convince me if I wrote a direct child selector using `>`. Here I don't specify how deep is hierarchy to find (or not find) `.list` class – Luca Detomi Oct 24 '16 at 09:22
  • @ZeevKatz Yes, I tried and it's my actual solution, but I would like to avoid (if possible) to override internal elements because in real case there are many CSS properties to be overridden, not only `font-weight` (this is only a simplified exampe) – Luca Detomi Oct 24 '16 at 09:24
  • 1
    @LucaDetomi: See `:not(.list) .toggle` would select all .toggle who are not descendants of `.list`. You have a clash. The outermost has but the `body` doesn't, and the inner one doesn't too. So which one do you want CSS to consider as the ancestor? – Harry Oct 24 '16 at 09:27
  • Possible duplicate of http://stackoverflow.com/questions/35051671/cascading-with-css-not-pseudo-class/35051684#35051684 I am hesitant to close only because you want a workaround which doesn't include targetting each level separately. – Harry Oct 24 '16 at 09:40
  • @Harry The `body > element` selector indeed resolved my particular issue at hand. – Serge Stroobandt Nov 13 '16 at 10:36

4 Answers4

5

I think you might want this:

.toggle {
  color: red;
  font-weight: bold;
}

div *:not(.list) .toggle {
  font-weight: normal;
}
Mike Harrison
  • 1,020
  • 2
  • 15
  • 42
3

:not does not support CSS Combinators.

Your only way to do this is:

.toggle {
  color: red;
}

.toggle {
  font-weight:bold;
}

.list .toggle {
  /* Override previous */
} 

Fiddle

Kevin Kopf
  • 13,327
  • 14
  • 49
  • 66
Zeev Katz
  • 2,273
  • 2
  • 16
  • 42
  • 2
    Not strictly true. There is nothing in the RFC about not supporting combinators. While `:not(.class) .otherClass` does not work, `:not(.class) > .otherClass` works fine. Here's proof: https://jsfiddle.net/k0m7512j/ However, in the circumstances OP presented, your answer is the correct one. – Kevin Kopf Mar 13 '20 at 02:35
2

I tried so many times but this is the only way I can do:

.toggle {
  color: red;
  font-weight:bold;
}

.list .toggle{
  //override
  font-weight:normal;
}

This is how to use :not the right way: add specialToggle for elements you do not want to select

<a href="#!" class="toggle specialToggle">SubToggle</a>

and then css:

.toggle {
  color: red;
}

.toggle:not(.specialToggle) {
  font-weight:bold;
}

https://jsfiddle.net/s249tyur/3/

Jared Chu
  • 2,757
  • 4
  • 27
  • 38
1

If the structure is always going to be the same you could try using the greater-than sign (>), it means only apply the style to the immediate children of the class.

.container > .toggle {
  font-weight:bold;
}

Or if the container is not always going to have the same class, but is always a div element you could use:

div > .toggle {
  font-weight:bold;
}
CamBarker
  • 41
  • 7
  • Please don't call a greater-than sign a chevron. > is not the same as ›. The situation on this site is bad enough as it is, with people using less-than and greater-than signs as chevrons, making the words inbetween come out invisible. – Mr Lister Oct 24 '16 at 11:42
  • Edited, thank you, i was not aware that it was an issue to used to using the terms around the office. – CamBarker Oct 24 '16 at 13:32
  • Well, the issue is that people use them as quotation marks in posts here, and the system handles them as HTML tags. So e.g. people write "I hit " and it comes out as "I hit " because unknown HTML tags are ignored. – Mr Lister Oct 24 '16 at 14:27
  • **greater-than sign (>) only selects immediate children** - This saved my day. Thanks! – Naveen Jul 18 '17 at 07:53