Reputation: 7640
I have the following code :
radio.component
<div [class]="'radio-container ' + cssClass || ''">
<div class="radio" [ngClass]="{ checked: checked, disabled: disabled, enabled: !disabled }">
<input type="checkbox" [disabled]="disabled" [ngModel]="checked" (click)="click($event)" />
<span class="checkmark"></span>
</div>
<div class="ml-2">
<ng-content></ng-content>
</div>
</div>
radio.scss
@import '~src/assets/styles/variables';
/* stylelint-disable no-descending-specificity */
.radio-container {
position: relative;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
margin: 0;
display: inline-flex;
.radio {
height: 16px;
width: 16px;
input {
height: 16px;
width: 16px;
position: absolute;
opacity: 0;
z-index: 2;
}
.checkmark {
position: absolute;
top: 0;
left: 0;
height: 16px;
width: 16px;
border-radius: 16px;
box-shadow: inset 1px 1px 2px 0 rgba(0, 0, 0, 0.2);
}
.checkmark::after {
content: '';
width: 8px;
height: 8px;
border-radius: 100%;
left: 3px;
top: 3px;
align-items: center;
position: relative;
display: inline-block;
visibility: visible;
border: 2px solid transparent;
}
&.enabled {
input {
cursor: pointer;
}
.checkmark {
border: solid 1px $placeholder;
background-color: $white;
}
.checkmark::after {
background-color: $white;
}
&.checked {
.checkmark {
background-color: $primary;
}
.checkmark::after {
display: block;
}
}
&:hover input ~ .checkmark {
border: solid 1px $primary;
}
&:focus input ~ .checkmark {
border: solid 1px $primary;
}
}
&.disabled {
input {
cursor: not-allowed;
}
.checkmark {
border: solid 1px $placeholder;
background-color: $border;
box-shadow: none;
}
&.checked {
.checkmark {
border: solid 1px $placeholder;
background-color: $white;
}
/* Show the checkmark when checked */
.checkmark::after {
display: block;
background-color: $border;
}
}
}
}
}
The div can be either enabled, or disabled, and I want to apply the correct css accordingly. The thing is, I have warning for stylelint saying that there shouldn't be descending specificity.
https://stylelint.io/user-guide/rules/no-descending-specificity
I know in my code it will be either one or the other class, so I disabled the rule, but I wonder if there might be a better way without disabling it.
I tried some refactoring but always end up with wrong code or the same problem
Upvotes: 4
Views: 1301
Reputation: 31
Stylelint does not know that .disabled
and .enabled
are mutually exclusive, but as they are, you do not need to use both class names. If you made enabled the default, you could generate compact CSS that fullfills the linter rules without giving up the readability benefit of SCSS nesting.
Then you could get rid of the redundant enabled class:
[ngClass]="{ checked: checked, disabled: disabled }
After that, you still have the tricky input / checkmark combinations.
You could split the last &.disabled
block into two blocks and put both directives with the sibling selectors in between. None of these are long blocks, so it is still readable after refactoring.
Your SCSS code would look like this:
.radio-container {
position: relative;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
margin: 0;
display: inline-flex;
.radio {
height: 16px;
width: 16px;
input {
height: 16px;
width: 16px;
position: absolute;
opacity: 0;
z-index: 2;
}
.checkmark {
position: absolute;
top: 0;
left: 0;
height: 16px;
width: 16px;
border-radius: 16px;
box-shadow: inset 1px 1px 2px 0 rgba(0, 0, 0, 0.2);
}
.checkmark::after {
content: '';
width: 8px;
height: 8px;
border-radius: 100%;
left: 3px;
top: 3px;
align-items: center;
position: relative;
display: inline-block;
visibility: visible;
border: 2px solid transparent;
}
input {
cursor: pointer;
}
.checkmark {
border: solid 1px $placeholder;
background-color: $white;
}
.checkmark::after {
background-color: $white;
}
&.checked {
.checkmark {
background-color: $primary;
}
.checkmark::after {
display: block;
}
}
&.disabled {
input {
cursor: not-allowed;
}
.checkmark {
border: solid 1px $placeholder;
background-color: $border;
box-shadow: none;
}
}
&:hover input ~ .checkmark {
border: solid 1px $primary;
}
&:focus input ~ .checkmark {
border: solid 1px $primary;
}
&.disabled {
&.checked {
.checkmark {
border: solid 1px $placeholder;
background-color: $white;
}
/* Show the checkmark when checked */
.checkmark::after {
display: block;
background-color: $border;
}
}
}
}
}
To verify it still produces the intended styles and behavior, we should have started with a minimal reproducible example using a code snippet in the first place, converting SASS and Angular into plain CSS and HTML, like this codepen
https://codepen.io/flingolf/pen/xxWQLvJ
Upvotes: 1