If I use this css, the span's text color is determined by its closest parent (i.e. text is blue):
.red {
color: red;
}
.blue {
color: blue;
}
.green {
color: green;
}
<div class="green">
<div class="red">
<div class="blue">
<div class="my-component">
<span>Hello World</span>
</div>
</div>
</div>
</div>
However, I want this behavior for .my-component specifically. I therefore added .my-component to my selector but suddenly, the span's text color is determined by the definition order (i.e. text is green):
.red .my-component {
color: red;
}
.blue .my-component {
color: blue;
}
.green .my-component {
color: green;
}
<div class="green">
<div class="red">
<div class="blue">
<div class="my-component">
<span>Hello World</span>
</div>
</div>
</div>
</div>
Why is this?
EDIT
Ok, so I messed up a bit here. As noted in the comments, I was mostly surprised that the distance between .red and .my-component did not affect specificity. However, my second question was the one I was really interested in. This question has already received a lot of great answers to the first question, so I'm reverting this question to its original state and will split the second question off into a new one. Thank you all for the great answers!
Given that the question was (originally) titled: "Can a component be styled based on its closest parent in pure CSS?" and looking at the original examples given
you can do it like this:
.red > .my-component {
color: red;
}
.blue > .my-component {
color: blue;
}
.green > .my-component {
color: green;
}
<div class="green">
<div class="red">
<div class="blue">
<div class="my-component">
<span>Hello World</span>
</div>
</div>
</div>
</div>
The > demands a direct parent-child relationship. A "grandparent" will have no effect on the target element's formatting.
However, the above snippet will not work if the target div is placed several levels under the innermost "colored" div.
This is all determined by Specificity:
Specificity is the algorithm used by browsers to determine the CSS declaration that is the most relevant to an element, which in turn, determines the property value to apply to the element. The specificity algorithm calculates the weight of a CSS selector to determine which rule from competing CSS declarations gets applied to an element.
With this being said, you can use more specific selectors such as the child combinator > with reference to the element to specify styles. You'll notice the more specific I get with the selectors that it will take precedence over other styles.
.red .my-component {
color: red;
}
.blue > .my-component span {
color: blue;
}
.green .my-component {
color: green;
}
<div class="green">
<div class="red">
<div class="blue">
<div class="my-component">
<span>Hello World</span>
</div>
</div>
</div>
</div>
If I were to use .green > .red > .blue > .my-component span in the last part of the CSS then this would take precedence because it is more specific. An example of that is below.
.red .my-component {
color: red;
}
.blue > .my-component span {
color: blue;
}
.green > .red > .blue > .my-component span {
color: green;
}
<div class="green">
<div class="red">
<div class="blue">
<div class="my-component">
<span>Hello World</span>
</div>
</div>
</div>
</div>
So this happens because the code below:
.red {color: red;}
.blue {color: blue;}
.green {color: green;}
influences the color of the element and its children.
Since one children is inside the another and CSS selectors here have the same priority then the one that is the cloest (the last) has the final word.
The color value is inherited but every time changed because of your classes. That's why the sequence in html has a meaning.
.red .my-component {color: red;}
.blue .my-component {color: blue;}
.green .my-component {color: green;}
In the second case you are targeting only .my-components inside the proper class elements so when you change color to red, you are then changing it to blue and at last to green. That's why the sequence in css file has a meaning and not in html.
I hope this will help.
I'm trying to style all my main tags based on a certain theme.
If a section's class is red, all of of it's inner tags should use the red style regardless of if that section is inside another section which uses the yellow style.
So my question is how do I restrict the inner tags of a section/div/nav etc, to only use the style of the first descendant it encounters.
Note: I do not want to rely on the order of which I declare my tags.
.red input {
background-color: red;
}
.red article {
background-color: red;
}
.red p {
background-color: red;
}
/*.. other tags.. */
.yellow input {
background-color: yellow;
}
.yellow article {
background-color: yellow;
}
.yellow p {
background-color: yellow;
}
/*.. other tags.. */
.blue input {
background-color: blue;
}
.blue article {
background-color: blue;
}
.blue p {
background-color: blue;
}
/*.. other tags.. */
<section class="yellow">
<section class="blue">
<form>
<input type="button" value="This should use the blue theme" />
</form>
</section>
<section class="red">
<article>
<p>This should use the red theme</p>
<!-- This is instead yellow, how do I fix that? -->
</article>
</section>
<section class="yellow">
<nav>
<p>This should use the yellow theme</p>
</nav>
</section>
<p>This should be yellow.</p>
</section>
UPDATE
Okay so I've tried the given solutions and they work with the given example but as soon as I expand the html code to something more complex it doesn't work anymore.
The thing is that since I have to build a general theme, I cannot use css rules that depend on the order of how the html is built. A user should be able to build its website and regardless of how the html is built the correct styles should be applied.
So if the user gives a container tag (nav, section, div, aside, etc.) the class dark-theme, yellow-theme or whatever other theme, all of its children should use that style UNLESS a child container has also specified its own theme.
Is it just not possible? :(
Ex:
section class=yellow-theme
p: use yellow-theme
aside: use yellow-theme
div class=red-theme
ul: use red-theme *not yellow
p: use red-theme *not yellow
footer class=blue-theme
a: use blue-theme *not red not yellow
h3: use blue-theme *not red not yellow
div class=yellow-theme
header: use yellow-theme *not blue * not red
form: user yellow-theme *not blue *not red
<!--This could go on forever and in any order with any tags-->
css:
.yellow-theme anytag{
/* Style any attributes needed: borders, colors, fonts, margins, paddings, etc. */
}
/* Do this for all the tags that needs to be styled */
.red-theme anytag{
/* Style any attributes needed: borders, colors, fonts, margins, paddings, etc. */
}
/* Do this for all the tags that needs to be styled */
.blue-theme anytag{
/* Style any attributes needed: borders, colors, fonts, margins, paddings, etc. */
}
/* Do this for all the tags that needs to be styled */
Any selector-only solution requires you to make assumptions about your markup that may or may not be within your control since the specificity of two contextual selectors is always the same regardless of how close the ancestor is to each descendant that is matched, and any solution that makes use of inheriting the actual properties themselves requires you to apply them to the .red, .yellow and .blue sections, which may not be desired. For example, you'd have to apply background-color to the sections in order for background-color: inherit to work on the descendants, but you may not want the sections themselves to have any background color, so that won't be an option to you.
Custom properties allow descendants to inherit values from their closest ancestors without polluting other properties in this manner, and without other cascading rules getting in the way (competing rules with equally specific contextual selectors, etc). You'll only be able to do this reliably with custom properties for this reason.
.red {
--color: red;
}
.yellow {
--color: yellow;
}
.blue {
--color: blue;
}
input, article, p {
background-color: var(--color);
}
<section class="yellow">
<section class="blue">
<form>
<input type="button" value="This should use the blue theme" />
</form>
</section>
<section class="red">
<article>
<p>This should use the red theme</p>
</article>
</section>
<section class="yellow">
<nav>
<p>This should use the yellow theme</p>
</nav>
</section>
<p>This should be yellow.</p>
</section>
This porblem is a little bit difficult if you want to solve it with all elements.
You have to think the other way: NOT "a rule is valid until there is another rule" BUT "the closest rule is valid".
How to achieve this?
First set a rule for all elements that are grandchildren except the form tag (perhaps also the ol, ul, nav, ... tags) that the background-color shell inherit. Now all this elements inherit theire background-color from the parent element.
Second set one rule for each theme that defines the background-color of all direct children. Here you have to take a look at the problem with the form tag. the form tag has no inheritage (see above) so the children of the form will not get the rule from the closest theme parent. So you have to setup an extra rule for this case.
All in all:
*.color * > *:not(form):not(html):not(body) {
background-color:inherit!important;
}
.red > *:not(form):not(.color), .red > form > *:not(.color) {background-color: red!important}
.yellow > *:not(form):not(.color), .yellow > form > *:not(.color) {background-color: yellow!important}
.blue > *:not(form):not(.color), .blue > form > *:not(.color) {background-color: blue!important}
(.color is a css class that all sections have, that also have the css class .red or .yellow or .blue)
the > - signs are important
you can mix up all the rules.
EDIT Now I see that !important is not neccessary :)
You can also write
*.color * > *:not(form):not(html):not(body) {
background-color:inherit;
}
.blue > *:not(form):not(.color), .blue > form > *:not(.color) {background-color: blue}
.red > *:not(form):not(.color), .red > form > *:not(.color) {background-color: red}
.yellow > *:not(form):not(.color), .yellow > form > *:not(.color) {background-color: yellow}
EDIT2 if you want to style a specific tag in a theme, you have to add the rules in the following way.
1) Add all css attributes that you want to style to the first rule of the set:
*.color * > *:not(form):not(html):not(body) {
background-color:inherit;
color:inherit;
}
2) replace the asterisk by the tag name
.blue > *:not(form):not(.color), .blue > form *:not(.color) {background-color: blue}
.red > *:not(form):not(.color), .red > form *:not(.color) {background-color: red}
.yellow > *:not(form):not(.color), .yellow > form *:not(.color) {background-color: yellow}
.blue > input:not(form):not(.color), .blue > form input:not(.color) { color:white; }
.red > input:not(form):not(.color), .red > form input:not(.color) { color: green; }
.yellow > input:not(form):not(.color), .yellow > form input:not(.color) { color: purple; }
3) have a look at the > - signs! I removed it at one position to make it work with all tags.
To target only the direct descendant of an element, you can use the direct descendant operator: >:
.red > input {
background-color: red;
}
And to go one step better, you can replace all repetitions like so, instead of having to manually declare each element:
.red > * {
background-color: red;
}
.yellow > * {
background-color: yellow;
}
.blue > * {
background-color: blue;
}
Try This :
.yellow > *:not(form):not(section), .yellow form * {background-color: yellow !important}
.blue > *:not(form):not(section), .blue form * {background-color: blue !important}
.red > *:not(form):not(section), .red form * {background-color: red !important}
.yellow > *:not(form):not(section), .yellow form * {background-color: yellow !important}
.blue > *:not(form):not(section), .blue form * {background-color: blue !important}
.red > *:not(form):not(section), .red form * {background-color: red !important}
<section class="yellow">
<section class="blue">
<form>
<input type="button" value="This should use the blue theme" />
</form>
</section>
<section class="red">
<article>
<p>This should use the red theme</p>
<!-- This is instead yellow, how do I fix that? -->
</article>
</section>
<section class="yellow">
<nav>
<p>This should use the yellow theme</p>
</nav>
</section>
<p>This should be yellow.</p>
</section>
Not sure if I understand your question, so just comment if I'm wrong.
Increase the specificity of the style so that will not be overridden that easily.
.red > article > p {
background-color: red;
}
.red input {
background-color: red;
}
.red article {
background-color: red;
}
.red > article > p {
background-color: red;
}
/*.. other tags.. */
.yellow input {
background-color: yellow;
}
.yellow article {
background-color: yellow;
}
.yellow p {
background-color: yellow;
}
/*.. other tags.. */
.blue input {
background-color: blue;
}
.blue article {
background-color: blue;
}
.blue p {
background-color: blue;
}
/*.. other tags.. */
<section class="yellow">
<section class="blue">
<form>
<input type="button" value="This should use the blue theme" />
</form>
</section>
<section class="red">
<article>
<p>This should use the red theme</p>
<!-- This is instead yellow, how do I fix that? -->
</article>
</section>
<section class="yellow">
<nav>
<p>This should use the yellow theme</p>
</nav>
</section>
<p>This should be yellow.</p>
</section>
I tried this and it works, regardless of what element is it as long as you define the parent, hope this helps
body > :first-child
{
background-color: #ff0000;
}
* {
color: yellow
}
.outermost {
color: blue
}
.middle {
color: red
}
<div class="outermost">
<div class="middle">
<p>Some Text</p>
</div>
</div>
I expect the color of <p>Some Text </p> to be red because <div class="middle"> is its parent. However, the color ends up as yellow. This seems counter-intuitive because the global selector is less specific than the parent container. Why does the p element inherit from global, and how can it be changed so that it inherits from the parent container?
As #j08691 notes in his comment, the universal selector * has no effect on specificity:
* {
color: yellow;
}
.middle {
color: red;
}
<div class="middle">
<p>Some Text</p>
</div>
If you'd like the specificity to operate under normal effects change the * to body:
body {
color: yellow;
}
.middle {
color: red;
}
<div class="middle">
<p>Some Text</p>
</div>
You're conflating inheritance with specificity. Those aren't the same thing; they're totally unrelated concepts in CSS.
It's true that the global selector has a much lower specificity than the .middle class selector, but that's irrelevant because the .middle selector isn't targeting your p element; it's targeting the p element's parent.
Normally that would be sufficient to make p use red text, because, by default, p has its color property set to the special value called inherit, which causes it to inherit its color from it's parent element. But p isn't using the default value (inherit) for its color property, because you have a matching rule telling explicitly to use yellow instead:
* {
color: yellow;
}
Inheritance doesn't even come into play here, because your p element isn't set to inherit from it's parent in the first place.
You can override that behavior using a selector with a higher specificity that targets the element containing your text (not just one of its ancestors) explicitly telling it to inherit from its parent:
* {
color: yellow;
}
.outermost {
color: blue;
}
.middle {
color: red;
}
.middle > p {
color: inherit; // This overrides the rule defined by the global selector above
}
<div class="outermost">
<div class="middle">
<p>Some Text</p>
</div>
</div>
Or alternately, you could just stop using the global selector and instead rely on inheritance to set the text color for most of your elements:
body {
color: yellow;
}
.outermost {
color: blue;
}
.middle {
color: red;
}
<div class="outermost">
<div class="middle">
<p>Some Text</p>
</div>
</div>
Note that using the global selector for this sort of thing is usually discouraged anyway, for numerous reasons.
To help you better understand why your current code isn't working, here's essentially what it's doing:
<div style="color:blue;"> <!-- Matches * and .outermost. Result: Blue -->
<div style="color:red;"> <!-- Matches * and .middle. Result: Red -->
<p style="color:yellow;">Some Text</p> <!-- Matches *. Result: yellow -->
</div>
</div>
This is how you would target the font inside the "middle" class https://jsfiddle.net/DIRTY_SMITH/cfckvvzw/3/
.middle > p {
color: red
}
Guyz i m completely new on css so i have this quiestions.....
h1 {
color: red
}
p{
color: blue
}
#ftx {
color: green
}
<h1>It appears fine red</h1>
<p>Pretty good appears blue</p>
<div id="ftx">
<h1> why doesn't it appears green?</h1>
<p/>Neither it appears green</p>
</div>
Why doesn't the div tag inherit h1 and p?
why doesn't the ftx id inherit the h1 and p tag inside the div tag?
The style indicated does apply to the text in the div unless it is overriden by other styles.
In the snippet below, you can see that the span is green because no other styling has been applied.
That is not the case for the h1 and p whether the existing styles apply because they have not been overridden.
h1 {
color: red
}
p {
color: blue
}
#ftx {
color: green
}
div {
border: 1px solid grey;
}
<h1>It appears fine red</h1>
<p>Pretty good appears blue</p>
<div id="ftx">
<h1> why doesn't it appears green?</h1>
<span>Lorem ipsum dolor sit.</span>
<p>Neither it appears green</p>
</div>
I want to toggle a single class .active on a div id="slot1".
The div has 2 child divs. When .active is NOT applied to the div, one child1 is yellow, child2 is green.
When I apply do something like $("#slot").addClass("active"), I want child1 to be blue and child2 to be red.
How do I write the css for the "children" so that toggling .active on their parent "slot" makes them switch states
.normal{}
.active{}
.a{color:yellow;}
.b{color:green;}
.a [when .active is applied to my daddy] {color:blue;}
.b [when .active is applied to my daddy] {color:red;}
<div id="slot1" class="normal">
<div class="a">normal I'm yellow, with active I'm blue</div>
<div class="b">normal I'm green, with active I'm red</div>
</div>
<div id="slot2" class="normal active">
<div class="a">normal I'm yellow, with active I'm blue</div>
<div class="b">normal I'm green, with active I'm red</div>
</div>
Normal
.normal .a {
background: yellow;
}
Active
.normal.active .a {
background: blue;
}
For the other children it's equivalent, see JSFiddle
If you want the to select on the direct ancestor only (daddy), you must use the child selector >
.normal > .a {
background: yellow;
}
.normal.active > .a {
background: blue;
}
.a{color:yellow;}
.b{color:green;}
#slot1.active .a, #slot2.active .a {color:blue;} /*No daddy selector, but you can just get the child of .active*/
#slot1.active .b, #slot2.active .b {color:red;}