Reputation: 3130
I have buttons inside a button group. Button groups come in different sizes, e.g. button-group-large
. My goal is to avoid having to explicitly set the size on each button in a button group by letting it infer the size from the button group. That is, instead of
<div class="button-group-large">
<button class="button-large">Foo</button>
<button class="button-large">Bar</button>
</div>
I would rather write this:
<div class="button-group-large">
<button>Foo</button>
<button>Bar</button>
</div>
I can do it like this (in SASS):
.button-group-large {
button { @extend .button-large; }
}
This works but creates the following problem. If one of my buttons has a special class, the .button-large
class will take precedence. That is, if I do
<div class="button-group-large">
<button class="special">Foo</button>
<button>Bar</button>
</div>
Then any attribute that differs between .special
and .button-large
will get the .button-large
value instead of the .special
value. I want this to be the opposite; .special
should win here. (As a real world example, .special
might set the a "primary" button color).
Here's a jsfiddle illustrating the problem: https://jsfiddle.net/wwr63qmv/3/
As a reference point, Bootstrap button groups avoid this problem by requiring the classes to be set individually on each button, rather than on the button group. That may be the only answer. Is there some other way to get the .special
class to win here?
Upvotes: 1
Views: 727
Reputation: 89790
The problem that you are facing is not due to Sass or the @extend
directive. It is how CSS works. If multiple selectors point to the same element then the most specific selector wins (or) if the specificity is same then the latest selector defined in the file wins.
The SCSS code in your fiddle will produce the below output when compiled:
.button, ul.button-group li button { /* check this selector */
border: 1px solid black;
color: black;
border-radius: 2px;
}
.special-button { /* and this */
border: 1px solid green;
color: green;
}
ul.button-group {
margin: 10px;
}
ul.button-group li {
list-style-type: none;
display: inline-block;
padding: 5px;
}
p {
font-family: monospace;
}
Both these selectors - ul.button-group li button
and .special-button
will target the button which has class as .special-button
. The specificity of the first selector is 013 (because it has 1 class and 3 type selectors as part of the full complex selector) whereas that for the second selector is 010 (as it has only one class selector). So, by nature the first selector wins and only properties specified under it applies to the element.
In order for .special-button
styles to apply, that selector's specificity should be increased. This can be done simply by changing the selector to ul.button-group li button.special-button
but it means that the selector would now target only button
with class='special-button'
which are within a li
whose ul
parent has class='button-group'
. That makes it very specific and means the properties won't apply if the button.special-button
is outside ul.button-group li
.
The other option would be to extend the .special-button
also within the li
like below:
ul.button-group {
margin: 10px;
li {
list-style-type: none;
display: inline-block;
padding: 5px;
button {
@extend .button;
&.special-button { /* note this */
@extend .special-button;
}
}
}
}
Upvotes: 1