1

In CSS, can you target an element, then exclude instances of it based on parent wrapper elements higher up the DOM?

For example:

HTML

<div class="wrap">
    <ul>
         <li>link</li>
         <li>link</li>
         <li>link</li>
    </ul>
</div>
<ul>
     <li>link</li>
     <li>link</li>
     <li>link</li>
</ul>

CSS

li {
    color:red;
}
li:not(.wrap li) {
    colour:blue;
}

So in this instance, I want to exclude the first series of <li> tags based on their parent wrapper. Is this achievable with CSS? (and I don't mean just target .wrap li and apply the desired styles there, as in my case I have to exclude)

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
Timmah
  • 1,283
  • 2
  • 10
  • 26
  • That's complicated. Why not just target all `li`s and make them blue. Then target the `.wrap li`, and make them red? – Vincent McNabb May 17 '15 at 23:54
  • http://stackoverflow.com/questions/7084112/css-negation-pseudo-class-not-for-parent-ancestor-elements http://stackoverflow.com/questions/20869061/is-the-css-not-selector-supposed-to-work-with-distant-descendants – BoltClock May 18 '15 at 03:55

1 Answers1

4

In CSS, can you target an element, then exclude instances of it based on parent wrapper elements higher up the DOM?

No, not the way you seem to be attempting with:

li:not(.wrap li)

You could, though, use instead a more simple approach of styling all <li> elements, and then specifically styling those elements that are descendants of an ancestor with the wrap class-name:

li {
    /* generic styles for <li> elements */
}
.wrap li {
    /* specific styles for <li> elements that are
       descendants of elements with a class of '.wrap' */
}

li {
  color: blue;
}
.wrap li {
  color: red;  
}
<div class="wrap">
    <ul>
         <li>link</li>
         <li>link</li>
         <li>link</li>
    </ul>
</div>
<ul>
     <li>link</li>
     <li>link</li>
     <li>link</li>
</ul>

Note that the following was removed from the above portion of the answer, due to its fragility - having to escape the period in the selector, and the fact that it's open to accidentally being overwritten by any ancestor having the 'wrap' class-name:

:not(\.wrap) li

li {
  color: red;
}
div:not(\.wrap) li {
  color: blue;  
}
<div class="wrap">
    <ul>
         <li>link</li>
         <li>link</li>
         <li>link</li>
    </ul>
</div>
<ul>
     <li>link</li>
     <li>link</li>
     <li>link</li>
</ul>
David Thomas
  • 249,100
  • 51
  • 377
  • 410
  • 1
    For anyone wondering, what escaping the period in `\.wrap` really does is transform it from a class selector into a *type selector*. Since an element of one type cannot be another, this makes `div:not(\.wrap)` similar to `div:not(p)`, i.e. a guaranteed match for all div elements, albeit [with slightly increased specificity](http://stackoverflow.com/questions/28299817/can-type-selectors-be-repeated-to-increase-specificity/28300471#28300471). The class attribute is completely removed from the equation. If you wrapped the second ul in its own div, the selector would match all li elements. – BoltClock May 18 '15 at 04:28