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;}
Related
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.
why all elements were colored on red?
<div class="parent">
<span>1</span>
<p>2</p>
<h1>3</h1>
</div>
.parent:nth-child(1) {
color: red;
}
.parent:nth-child(2) {
color: green;
}
.parent:nth-child(3) {
color: blue;
}
I thought that the elements would be properly colored. span, p, h1 are the children of the element div?
.parent:nth-child(1) means "An element that is the first child of its parent and which is a member of the parent class".
It won't match the span, p or h1 because they do not have class="parent".
The inherit the red colour from their parent which does have that class and is the first child in its parent.
You need a child or descendant combinator in there:
.parent > :nth-child(1)
.parent :nth-child(1)
.red p {
color: red;
}
.blue p {
color: blue;
}
<div class="blue">
<p> first </p>
<div class="red">
<p> second </p>
</div>
</div>
I assumed the first would have been blue and the second as red, but that isn't the case. Why are both paragraphs blue?
Both paragraphs are blue due to the "C" in CSS - which stands for cascading. Review the MDN docs to see how CSS rules are applied and inherited.
In your case all of <p> elements are blue because the .blue p selector is the last rule in your CSS and it overrides the .red p selector.
You can restructure your CSS like this to ensure that the <p> elements within the .red div are red.
.blue p {
color: blue;
}
.blue .red p {
color: red;
}
As you know:
.blue p matches any p tags within a .blue class.
.red p matches any p tags within a .red class.
Your <p> first </p> is within a blue class, so it matches the .blue p rule, and is rendered as blue.
<div class="red"> is within both a red class and a blue class, so we have a dilemma. The way CSS resolves this is by using whichever rule appeared last. In this case the .blue p rule appears last, and the text is rendered as blue.
CSS fix
If p tags are always going to be an immediate child of your color classes, you could do the following. The > is a descendant selector that only matches immediate descendants.
.red > p {
color: red;
}
.blue > p {
color: blue;
}
CSS fix 2
You can also do as Tom suggested. The reason why it works is because CSS rules that are more specific will overwrite CSS rules that are less specific. Even though the blue rule comes second because div .red p has two classes, it is more specific than .blue p.
.red p,
.blue .red p {
color: red;
}
.blue p,
.red .blue p {
color: blue;
}
However, this only takes your problem one level deeper. The red class in the following HTML will still be rendered blue.
<div class="blue">
<div class="blue">
<p> first </p>
<div class="red">
<p> second </p>
</div>
</div>
</div>
HTML fix
This is the method I would suggest you use. You can simply move your classes to the p tags:
<div>
<p class="blue"> first </p>
<div>
<p class="red"> second </p>
</div>
</div>
Other items to watch out for
There are other ways a CSS rule can get overridden. I would suggest you research CSS specificity.
Because you have given blue color to the parent div. This should be your structure.
<div class="blue">
<p>first</p>
</div>
<div class="red">
<p>second</p>
</div>
CSS code will be :
.red {
color: red;
}
.blue {
color: blue;
}
I've been trying to set different styles to the same class (when it appears for the second time in the markup) using the Subsequent-sibling combinator "~" but it seems it didn't work , maybe I'm omitting a detail with the use of "~" , also... Unfortunately I cannot change the html because it is generated by a cms
<div class="root">
<div class="container">
<div class="mosaic big">
<div>Red</div>
</div>
</div>
<div class="container">
<div class="mosaic medium">
<div>3</div>
</div>
</div>
<div class="container">
<div class="mosaic big">
<div>Blue</div>
</div>
</div>
<div class="container">
<div class="mosaic medium">
<div>4</div>
</div>
</div>
</div>
and this is the css
.root > .container > .mosaic.big {
color: red
}
.root > .container > .mosaic.big ~ .root > .container > .mosaic.big {
color: blue
}
also... here's a jsfiddle https://jsfiddle.net/chinoche/wd1rhg11/
Thanks in advance
Try this styling.
.root > .container > .mosaic.big {
color: red
}
.root > .container:nth-child(3) > .mosaic.big {
color: blue
}
OR
.root > .container > .mosaic.big {
color: red
}
.root > .container:nth-child(n+2) > .mosaic.big {
color: blue
}
From what ather answers suggested, i assumed this is what you want (you can comment if it doesn't fit edge cases):
So as i said, ~ only works with elements that have the same parent.
Note: it doesn't make it blue because it's the second .mosaic.big in a container, but because the container itself is not the first. To have a fully working solution without experimental features, you should need JS
CSS:
.root > .container > .mosaic.big {
color: red
}
.root > .container ~ .container > .mosaic.big {
color: blue
}
https://jsfiddle.net/wd1rhg11/5/
Sadly without changing the html you will not be able to use the subsequent sibling selector
The CSS next sibling selector will only match the immediate siblings of the class to the left of the operator. So for this to work the elements you use with this operator must have the same parent.
In addition the matching on the right hand side will begin at the element matched on the left hand side therefore you dont need to add the parent structure
.root > .container > .mosaic.big {
color: red
}
.root > .container > .mosaic.big ~ .mosaic.big {
color: blue
}
See updated
https://jsfiddle.net/wd1rhg11/4/
You may be able to acheive what you are trying to with javascript if possible
You can use nth-child(n) of '.mosaic' class:
.root > .container > .mosaic:nth-child(1).big {
color: red;
}
.root > .container > .mosaic:nth-child(3).big {
color: blue;
}
here`s jsfiddle
https://jsfiddle.net/andrewsilent/w8jjjsbz/
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;
}