Imagine I have a dynamically rendered page where I use classes class1
and class2
on some divs which contain each other:
<div class="class1">
...
<div class="class2">
...
<div class="insider">
I also have these selectors in my CSS:
.class1 .insider { ... }
.class2 .insider { ... }
Now the problem is that both selectors match the above .insider
and the one later in the CSS source code will win.
How can I make the selector win that has the classN
parent closest to the .insider
.
Below is a snippet where I reproduced my problem, I also showed my expectations with inline styles.
The .other
and .another
div
s are there to show that the depth of .insider is not known, so the direct child selector (>
) is out of the picture.
/* Layout: irrelevant to the issue */
.outer {
height: 100px;
width: 100px;
}
.inner {
display: inline-block;
height: 50px;
width: 50px;
margin: 25px 25px;
}
.insider {
text-align: center;
}
/* Colors: the visual part that should be fixed */
.class1 {
background-color: black;
}
.class2 {
background-color: lightgray;
}
.class1 .insider {
color: red;
}
.class2 .insider {
color: green;
}
<table>
<tr><th>Title</th><th>Actual</th><th>Expected</th><th>Explanation</th></tr>
<tr>
<td>Inside class1-2</td>
<td>
<div class="outer class1">
<div class="inner class2">
<div class="other">
<p class="insider">asdf</p>
</div>
</div>
</div>
</td>
<td>
<div class="outer" style="background-color: black;">
<div class="inner" style="background-color: lightgray;">
<div class="other">
<p class="insider" style="color: green;">asdf</p>
</div>
</div>
</div>
</td>
<td>The text color should be green because the closest styled parent is "class2" and not because ".class2 .insider" is declared after ".class1 .insider" in the CSS code. Swap the red and green styles in CSS and the text turns red.</td>
</tr>
<tr>
<td>Inside class2-1</td>
<td>
<div class="outer class2">
<div class="inner class1">
<div class="other">
<div class="another">
<p class="insider">asdf</p>
</div>
</div>
</div>
</div>
</td>
<td>
<div class="outer" style="background-color: lightgray;">
<div class="inner" style="background-color: black;">
<div class="other">
<div class="another">
<p class="insider" style="color: red;">asdf</p>
</div>
</div>
</div>
</div>
</td>
<td>The text color should be red because the closest styled parent is "class1".</td>
</tr>
<tr>
<td>Inside class2-1-2</td>
<td>
<div class="outer class2">
<div class="inner class1">
<div class="other class2">
<div class="another">
<p class="insider">asdf</p>
</div>
</div>
</div>
</div>
</td>
<td>
<div class="outer" style="background-color: lightgray;">
<div class="inner" style="background-color: black;">
<div class="other" style="background-color: lightgray;">
<div class="another">
<p class="insider" style="color: green;">asdf</p>
</div>
</div>
</div>
</div>
</td>
<td>The text color should be green because the closest styled parent is "class2", and not because the outermost styled parent is "class2", nor because of declaration order, see the first case.</td>
</tr>
</table>
All of the examples show this in the Chrome Dev Tools Inspector:
where it's visible that the green color wins because it has bigger line number.
.class1 .insider,
.class2 .class1 .insider{
color: red;
}
.class2 .insider,
.class1 .class2 .insider{
color: green;
}
The downside of this solution is as your N increase the number of selector you have to write also increase recursively. But it can be helped with a pre-processing library like SASS or LESS.
Demo:
/* Layout: irrelevant to the issue */
.outer {
height: 100px;
width: 100px;
}
.inner {
display: inline-block;
height: 50px;
width: 50px;
margin: 25px 25px;
}
.insider {
text-align: center;
}
/* Colors: the visual part that should be fixed */
.class1 {
background-color: black;
}
.class2 {
background-color: lightgray;
}
.class1 .insider,
.class2 .class1 .insider{
color: red;
}
.class2 .insider,
.class1 .class2 .insider{
color: green;
}
<table>
<tr><th>Title</th><th>Actual</th><th>Expected</th><th>Explanation</th></tr>
<tr>
<td>Inside class1-2</td>
<td>
<div class="outer class1">
<div class="inner class2">
<div class="other">
<p class="insider">asdf</p>
</div>
</div>
</div>
</td>
<td>
<div class="outer" style="background-color: black;">
<div class="inner" style="background-color: lightgray;">
<div class="other">
<p class="insider" style="color: green;">asdf</p>
</div>
</div>
</div>
</td>
<td>The text color should be green because the closest styled parent is "class2" and not because ".class2 .insider" is declared after ".class1 .insider" in the CSS code. Swap the red and green styles in CSS and the text turns red.</td>
</tr>
<tr>
<td>Inside class2-1</td>
<td>
<div class="outer class2">
<div class="inner class1">
<div class="other">
<div class="another">
<p class="insider">asdf</p>
</div>
</div>
</div>
</div>
</td>
<td>
<div class="outer" style="background-color: lightgray;">
<div class="inner" style="background-color: black;">
<div class="other">
<div class="another">
<p class="insider" style="color: red;">asdf</p>
</div>
</div>
</div>
</div>
</td>
<td>The text color should be red because the closest styled parent is "class1".</td>
</tr>
<tr>
<td>Inside class2-1-2</td>
<td>
<div class="outer class2">
<div class="inner class1">
<div class="other class2">
<div class="another">
<p class="insider">asdf</p>
</div>
</div>
</div>
</div>
</td>
<td>
<div class="outer" style="background-color: lightgray;">
<div class="inner" style="background-color: black;">
<div class="other" style="background-color: lightgray;">
<div class="another">
<p class="insider" style="color: green;">asdf</p>
</div>
</div>
</div>
</div>
</td>
<td>The text color should be green because the closest styled parent is "class2", and not because the outermost styled parent is "class2", nor because of declaration order, see the first case.</td>
</tr>
</table>
Edit with another N-independent version in which you only need to add selectors if your nested HTML layout get more complex:
.unique_class_name1 .insider,
[class~=unique_class_name] .unique_class_name1 .insider{
color: red;
}
.unique_class_name2 .insider,
[class~=unique_class_name] .unique_class_name2 .insider{
color: green;
}
In this version though, it is very important to make sure the pattern unique_class_name
is truly unique, since class~=unique_class_name
will hit all elements where the class attribute contains that key.
/* Layout: irrelevant to the issue */
.outer {
height: 100px;
width: 100px;
}
.inner {
display: inline-block;
height: 50px;
width: 50px;
margin: 25px 25px;
}
.insider {
text-align: center;
}
/* Colors: the visual part that should be fixed */
.unique_class_name1 {
background-color: black;
}
.unique_class_name2 {
background-color: lightgray;
}
.unique_class_name1 .insider,
[class~=unique_class_name] .unique_class_name1 .insider{
color: red;
}
.unique_class_name2 .insider,
[class~=unique_class_name] .unique_class_name2 .insider{
color: green;
}
<table>
<tr><th>Title</th><th>Actual</th><th>Expected</th><th>Explanation</th></tr>
<tr>
<td>Inside class1-2</td>
<td>
<div class="outer unique_class_name1">
<div class="inner unique_class_name2">
<div class="other">
<p class="insider">asdf</p>
</div>
</div>
</div>
</td>
<td>
<div class="outer" style="background-color: black;">
<div class="inner" style="background-color: lightgray;">
<div class="other">
<p class="insider" style="color: green;">asdf</p>
</div>
</div>
</div>
</td>
<td>The text color should be green because the closest styled parent is "class2" and not because ".class2 .insider" is declared after ".class1 .insider" in the CSS code. Swap the red and green styles in CSS and the text turns red.</td>
</tr>
<tr>
<td>Inside class2-1</td>
<td>
<div class="outer unique_class_name2">
<div class="inner unique_class_name1">
<div class="other">
<div class="another">
<p class="insider">asdf</p>
</div>
</div>
</div>
</div>
</td>
<td>
<div class="outer" style="background-color: lightgray;">
<div class="inner" style="background-color: black;">
<div class="other">
<div class="another">
<p class="insider" style="color: red;">asdf</p>
</div>
</div>
</div>
</div>
</td>
<td>The text color should be red because the closest styled parent is "class1".</td>
</tr>
<tr>
<td>Inside class2-1-2</td>
<td>
<div class="outer unique_class_name2">
<div class="inner unique_class_name1">
<div class="other unique_class_name2">
<div class="another">
<p class="insider">asdf</p>
</div>
</div>
</div>
</div>
</td>
<td>
<div class="outer" style="background-color: lightgray;">
<div class="inner" style="background-color: black;">
<div class="other" style="background-color: lightgray;">
<div class="another">
<p class="insider" style="color: green;">asdf</p>
</div>
</div>
</div>
</div>
</td>
<td>The text color should be green because the closest styled parent is "class2", and not because the outermost styled parent is "class2", nor because of declaration order, see the first case.</td>
</tr>
</table>
Have you tried specifying both rules for nesting and not nesting elements?
Like .c1 .c2 .insider, .c2 .insider { color: red;}
Other way would be to refactor your code.
.c2 .c1 .c3,
.c1 .c3 {
color: green;
}
.c1 .c2 .c3,
.c2 .c3 {
color: blue;
}
<div class="c1">
<div class="c2">
<div class="c3">C2 - blue</div>
</div>
</div>
<div class="c2">
<div class="c1">
<div class="c3">C1 - green</div>
</div>
</div>
<div class="c1">
<div class="c3">C1 - green</div>
</div>
<div class="c2">
<div class="c3">C2 - blue</div>
</div>
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