125

I have a hierarchical navigation menu in my sidebar that uses nested lists (<ul> and <li> tags). I am using a pre-made theme that already has styles for list items, but I want to alter the style for the top-level items but NOT have it apply to the sub-items. Is there an easy way to apply styles to the top-level list item tag WITHOUT having those styles cascade down to its children list items? I understand that I can explicitly add overriding styles to the sub-items but I'd really like to avoid having to duplicate all of that style code if there is an easy way to just say "apply these styles to this class and DO NOT cascade them down to any children elements". Here is the html I'm using:

<ul id="sidebar">
  <li class="top-level-nav">
    <span>HEADING 1</span>
    <ul>
      <li>sub-heading A</li>
      <li>sub-heading B</li>
    </ul>
  </li>
  <li class="top-level-nav">
    <span>HEADING 2</span>
    <ul>
      <li>sub-heading A</li>
      <li>sub-heading B</li>
    </ul>
  </li>
</ul>

So the CSS has styles for #sidebar ul and #sidebar ul li already, but I'd like to add additional styles to #sidebar .top-level-nav that do NOT cascade down to its sub-children. Is there any way to do this simply or do I need to rearrange all of the styles so the styles that were on #sidebar ul are now specific to certain classes?

3
  • 2
    I did search the site for similar questions and didn't find anything (not saying there isn't one, but I did look). If you know what it is could you please direct me to it? Thanks! Commented Jun 5, 2009 at 21:13
  • 1
    stackoverflow.com/questions/747308/breaking-css-inheritance | it pretty much says what Matthew answered. Commented Jun 5, 2009 at 21:17
  • 1
    So I take it the answer is "no, there is no way to do that simply -- you have to manually override every style setting on the sub-item" -- am I interpreting this correctly? Thanks again. Commented Jun 5, 2009 at 21:22

13 Answers 13

79

You either use the child selector

So using

#parent > child

Will make only the first level children to have the styles applied. Unfortunately IE6 doesn't support the child selector.

Otherwise you can use

#parent child child

To set another specific styles to children that are more than one level below.

Sign up to request clarification or add additional context in comments.

1 Comment

Could you show me this in action in JSFiddle? I tried to center a inline-block displayed div, but it still centers the text inside the div.
62

There is a property called all in the CSS3 inheritance module. It works like this:

#sidebar ul li {
  all: initial;
}

As of 2016-12, all browsers but IE/Edge and Opera Mini support this property.

6 Comments

@AndriusDobrotinas to become supported eventually? I seem to not completely grasp your comment. There is a PostCSS plugin that provides this feature, if you use PostCSS: github.com/maximkoretskiy/postcss-initial
@AndriusDobrotinas, Your comment is very nonconstructive. The answer was posted for the community's sake; try your hardest to see its benefit.
As of now, only IE and Opera Mini don't support it, all other major browsers do
@Boldewyn there is no 'default' value, as far as one can tell from the linked w3 doc...
I set it to initial, probably closest to what default must have meant, though, to be completely honest with you, I didn’t spend more than a few minutes researching... hope that’s ok.
|
39

As of yet there are no parent selectors (or as Shaun Inman calls them, qualified selectors), so you will have to apply styles to the child list items to override the styles on the parent list items.

Cascading is sort of the whole point of Cascading Style Sheets, hence the name.

2 Comments

This information is outdated since IE8. See the answer by Silviu Postavaru. Please consider to change the check to the more appropriate answer.
lol, I agree cascading is kinda the essence. But there should be a way to stop propagation from a specific parent that is intended to be different.
35

You can use the * selector to change the child styles back to the default

example

#parent {
    white-space: pre-wrap;
}

#parent * {
    white-space: initial;
}

2 Comments

That's a very handsome solution - especially if you do not know the parent's class.
I think I know the answer to this but is there anyway to set this inline? <div id="parent" style="white-space:pre-wrap;*white-space:initial;"/>
11

Wrapping with iframe makes parent css obsolete.

4 Comments

Funny that this is the worst maked answer because technically it is the only physical way to stop CSS inheritance. Not that I am arguing that you should use it this way.
I'd suggest not getting physical with CSS, leave it in the virtual world where it belongs!
Actually adding iframe made my child component invisible. Thoughts?
It's not the only physical way - custom elements will also work
6

Short answer is: No, it's not possible to prevent CSS inheritance. You can only override the styles that are set on the parents. See the spec:

Every element in an HTML document will inherit all inheritable properties from its parent except the root element (html), which doesn’t have a parent. -W3C

Apart from overriding every single inherited property. You can also use initial keyword, e.g. color: initial;. It also can be used together with all, e.g. all: initial;, that will reset all properties at once. Example:

.container {
  color: blue;
  font-style: italic;
}
.initial {
  all: initial;
}
<div class="container">
  The quick brown <span class="initial">fox</span> jumps over the lazy dog
</div>

Browser support tables according to Can I use...

  • all (Currently no support in both IE and Edge, others are good)
  • initial (Currently no support in IE, others are good)

You may find it useful by using direct children selector > in some cases. Example:

.list > li {
  border: 1px solid red;
  color: blue;
}
<ul class="list">
  <li>
    <span>HEADING 1</span>
    <ul>
      <li>sub-heading A</li>
      <li>sub-heading B</li>
    </ul>
  </li>
  <li>
    <span>HEADING 2</span>
    <ul>
      <li>sub-heading A</li>
      <li>sub-heading B</li>
    </ul>
  </li>
</ul>

The border style has been applied only to the direct children <li>s, as border is an non-inherited property. But text color has been applied to all the children, as color is an inherited property.

Therefore, > selector would be only useful with non-inherited properties, when it comes to preventing inheritance.

Comments

2

For example if you have two div in XHTML document.

<div id='div1'>
    <p>hello, how are you?</p>
    <div id='div2'>
        <p>I am fine, thank you.</p>
    </div>
</div>

Then try this in CSS.

#div1 > #div2 > p{
    color: red;
}

affect only 'div2' paragraph.

#div1 > p {
    color: red;
} 

affect only 'div1' paragraph.

Comments

2

You don't need the class reference for the lis. Instead of having CSS like

li.top-level-nav { color:black; }

you can write

ul#sidebar > li { color:black; }

This will apply the styling only to lis that immediately descend from the sidebar ul.

Comments

2

You may use Shadow Dom which is a new feature provided by browsers. Browser support is also pretty decent for the date.

Documentation: https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM

Comments

1

You could use something like jQuery to "disable" this behaviour, though I hardly think it's a good solution as you get display logic in css & javascript. Still, depending upon your requirements you might find jQuery's css utils make life easier for you than trying hacky css, especially if you're trying to make it work for IE6

Comments

1

You can wrap the element that you don't want to inherit any styles in a div with no style.

Something like this:

<div style='all: revert !important;'>
  Your content here
</div>

Comments

1

here's an live example using cascade, initial and all property:

div {
  border: 1px solid red;
  margin: 10px;
}

div p {
  color: red;
}

.initial {
  border-color: initial;
}

.initial p {
  color: initial;
}

.asterisk,
.asterisk * {
  border-color: initial;
  color: initial;
}

.all,
.all * {
  all: initial
}

https://jsbin.com/cosabusiwi/1/edit?html,css,output

Comments

0

just set them back to their defaults in the "#sidebar ul li" selector

1 Comment

Thanks for the answer. Yes I understand that I can set them back in the sub-item's style, but I'm trying to avoid that because I'm using a theme that I didn't create and I'm wondering if I can save a bunch of time by just using some "do-not-cascade: true" rule or something like that, instead of locating all the different styles for the ul's and li's which are scattered all over the place and then worrying about unintended consequences in other areas of the site.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.