Reputation: 911
I'm trying to theme some buttons according to their ancestors (not parents, especialy), so... I have the following HTML structure
<body class="theme-a">
<section class="container">
<form class="theme-b">
<div class="button-group">
<button type="button">Button B1</button>
<button type="button">Button B2</button>
</div>
<div class="button-group">
<button type="button">Button B3</button>
<button type="button">Button B4</button>
</div>
</form>
<form>
<div class="button-group">
<button type="button">Button A1</button>
<button type="button">Button A2</button>
</div>
<div class="button-group">
<button type="button">Button A3</button>
<button type="button">Button A4</button>
</div>
</form>
</section>
</body>
Well, as you can see, there are two themes .theme-a
and .theme-b
The CSS code, looks like:
.theme-a {
background: #999;
}
.theme-b {
background: #555;
}
.theme-a button {
background: #222;
}
.theme-b button {
background: #69C;
}
The problem is: if you switch the theme classes (A with B and B with A), you'll notice that the button on A theme (which has a closer ancestor with the theme class, keeps the styling of the far ancestor, the blue background rather than black one).
How can I achieve a proper specificity in a way that the button properties are set according to the closest ancestor?
Here's the link from JSfiddle: http://jsfiddle.net/XVaQT/1/
I hope that I explained in a clear way :)
Thanks
Upvotes: 5
Views: 899
Reputation: 82986
There's now a way to directly address this in Chrome and Edge, and hopefully the other browsers will follow soon. CSS scoping takes the proximity of the matching selector into account, allowing the declarations from the nearest matching ancestor to take precedence ahead of the order in which the CSS rules appear.
So in this example, for the first set of buttons, both the button rules match, but instead of the later rule using .theme-b
winning the cascade, the .theme-a
rule wins because the .theme-a
element is a nearer ancestor of the buttons.
.theme-a {
background: #999;
}
.theme-b {
background: #555;
}
@scope(.theme-a) {
button {
background: #222;
}
}
@scope(.theme-b) {
button {
background: #69C;
}
}
<body class="theme-b">
<section class="container">
<form class="theme-a">
<div class="button-group">
<button type="button">Button B1</button>
<button type="button">Button B2</button>
</div>
<div class="button-group">
<button type="button">Button B3</button>
<button type="button">Button B4</button>
</div>
</form>
<form>
<div class="button-group">
<button type="button">Button A1</button>
<button type="button">Button A2</button>
</div>
<div class="button-group">
<button type="button">Button A3</button>
<button type="button">Button A4</button>
</div>
</form>
</section>
</body>
Upvotes: 0
Reputation: 1
Here's a 2023 solution using :has
that styles a button based off the .theme-*
class on the closest ancestor, and allows unlimited nesting of .theme-*
classes on ancestors.
.theme-a:not(:has([class*='theme-'])) button {
/* theme-a button styles */
}
The selector is saying: "Give me all .theme-a
elements, but not ones with a nested theme-*
class inside them." (Specifically, not ones with a child element with a class attribute that contains theme-
.)
Upvotes: 0
Reputation: 5000
Thanfully, with CSS you can combine multiple selectors to specify the same styles for lots of elements, I updated your jsfiddle with a working example, just change the classes theme-a
and theme-b
, as you said in your question, to see it working: http://jsfiddle.net/cchana/XVaQT/3/
All I have done is add a second selector where you were just looking for a button
that is the descendant of an element with the class theme-a
:
.theme-a button {
background: #222;
}
It now also looks for a button
that is the descendant of an element with the class theme-b
that is itself a descendant of an element with the class theme-a
:
.theme-a button,
.theme-a .theme-b button {
background: #222;
}
There should be no need to add a !important
to your background
value as it will override the styles defined for .theme-b button
thanks to this selector being more specific.
Upvotes: 1