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.
!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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With