How do I prevent CSS inheritance?
CssCss Problem Overview
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?
Css Solutions
Solution 1 - Css
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.
Solution 2 - Css
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.
Solution 3 - Css
As of yet there are no parent selectors (or as http://www.shauninman.com">Shaun Inman calls them, http://www.shauninman.com/archive/2008/05/05/css_qualified_selectors">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.
Solution 4 - Css
You can use the * selector to change the child styles back to the default
example
#parent {
white-space: pre-wrap;
}
#parent * {
white-space: initial;
}
Solution 5 - Css
Wrapping with iframe makes parent css obsolete.
Solution 6 - Css
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.
Solution 7 - Css
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
Solution 8 - Css
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.
Solution 9 - Css
You don't need the class reference for the li
s. 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 li
s that immediately descend from the sidebar ul
.
Solution 10 - Css
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
Solution 11 - Css
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>
Solution 12 - Css
just set them back to their defaults in the "#sidebar ul li" selector