scss-root-selectors
v1.0.0
Published
Concise, DRY, maintainable and scalable SCSS solution for styling large scale projects
Downloads
24
Readme
##Express a conditional states/modes with regard to the root state (class)
###Motivation
Components have various modes which are turned on/off by toggling class names on the root node. Express SCSS concisely and refer to root node modes, without losing the scope you style and maintain the same DOM hierarchy inside the SCSS file.
Given a simple component CSS with some nesting:
.comp-root-selector {
> .child {
> .another-child {
color: blue;
}
}
}
.another-child
should get color: orange;
when .comp-root-selector
is appended with an additional class: .special
. Let's examine with using the built in ancestor selector (&
):
.comp-root-selector {
> .child {
> .another-child {
color: blue;
.special & {
color: orange
}
}
}
}
It will yield the following CSS, where .special
is an ancestor or .comp-root-selector
. Note the space between them:
.comp-root-selector > .child > .another-child {
color: blue;
}
.special .comp-root-selector > .child > .another-child {
color: orange;
}
If you need to have it on the same root selector, use the library's mixin:
.comp-root-selector {
> .child {
> .another-child {
color: blue;
@include when-root-has-class(special) {
color: orange;
}
}
}
}
Will yield the following (desired) CSS. Note: there is no space in .special.comp-root-selector
.
.comp-root-selector > .child > .another-child {
color: blue;
}
.special.comp-root-selector > .child > .another-child {
color: orange;
}
Similarly, the following SCSS mixins are available as part of the library: Classes modes for a selector:
when-root-has-class($class-name)
: when the specified classes is authored on the root level.when-root-has-any-class($class-names)
: one of the specified classes (one or many) is authored on the root levelwhen-root-has-all-classes($class-names)
: all specified classes (one or many) are authored on the root level
Pseudo class modes for a selector:
when-root-has-pseudo-class($pseudo-class)
: The specified pseudo class is authored on the root levelwhen-root-has-all-pseudo-classes($pseudo-classes)
: all specified pseudo classes are authored on the root levelwhen-root-has-any-pseudo-classes($pseudo-class-names)
: any of the specified pseudo classes are authored on the root level.
Attribute modes for a selector:
when-root-has-attr($pseudo-class)
: The specified attribute selector is authored on the root levelwhen-root-has-all-attrs($pseudo-classes)
: all specified attribute selector are authored on the root levelwhen-root-has-any-attrs($pseudo-class-names)
: any of the specified attribute selector are authored on the root level.create-attr-selector($name, $value)
: a shorthand for the [name="value"] attribute selector string. use as a constructor for convenience
Any combination:
when-root-has-all($class-names, $pseudo-class-names, $attr-selectors)
: all specified combination of class names, pseudo class names and attribute selectors, authored on the root level.when-root-has-any($class-names, $pseudo-class-names, $attr-selectors)
: any of the specified combination of class names/pseudo class names/attribute selectors are authored on the root level.
Advanced: Ancestor pseudo conditions:
when-parent-has-pseudo($pseudo-classes)
: if previous part of selector has the specified pseudo classes, apply the styling.when-ancestor-has-pseudo($pseudo-classes, $levels)
: when an ancestor up the selector has the specified pseudo classes, apply the styling. The ancestor is specified by an number of levels up the selector.- see root selector helpers
##Example: A custom checkbox
- Specified colors for various different modes (regular / hover / selected)
- Needs to have a "beautiful" mode which specifies different styling. (See Pen by @eitaneitan on CodePen.)
<label class="control-checkbox">
<input type="checkbox" class="input" />
<div class="content"></div>
</label>
.control-checkbox {
display: inline-block;
cursor: pointer;
> .input {
display: none;
+ .content {
width: 28px;
height: 28px;
background-color: red;
border: solid 3px blue;
}
&:checked + .content {
background-color: green;
}
}
&:hover > .input + .content {
background-color: yellow;
}
&.beautiful {
> .input {
+ .content {
background-color: cyan;
border-color: lime;
border-radius: 50%;
}
&:checked + .content {
background-color: orange;
}
}
&:hover {
> .input + .content {
background-color: grey;
}
}
}
}
A better approach: DRY, concise, extensible, refactorable, DOM-like structure:
.control-checkbox {
display: inline-block;
cursor: pointer;
> .input {
display: none;
+ .content {
width: 28px;
height: 28px;
background-color: red;
border: solid 3px blue;
@include when-parent-has-pseudo(checked) {
background-color: green;
}
@include when-root-has-pseudo-class(hover) {
background-color: yellow;
}
@include when-root-has-class(beautiful) {
background-color: cyan;
border-radius: 50%;
border-color: lime;
@include when-parent-has-pseudo(checked) {
background-color: orange;
}
@include when-root-has-pseudo-class(hover) {
background-color: grey;
}
}
}
}
}
Compiled CSS Code:
.control-checkbox {
display: inline-block;
cursor: pointer;
}
.control-checkbox > .input {
display: none;
}
.control-checkbox > .input + .content {
width: 28px;
height: 28px;
background-color: red;
border: solid 3px blue;
}
.control-checkbox > .input:checked + .content {
background-color: green;
}
.control-checkbox:hover > .input + .content {
background-color: yellow;
}
.beautiful.control-checkbox > .input + .content {
background-color: cyan;
border-radius: 50%;
border-color: lime;
}
.beautiful.control-checkbox > .input:checked + .content {
background-color: orange;
}
.beautiful.control-checkbox:hover > .input + .content {
background-color: grey;
}
##Recommended scss-lint configuration It really assists with getting things in order:
DeclarationOrder:
enabled: true
DisableLinterReason:
enabled: true
DuplicateProperty:
enabled: true
SingleLinePerProperty:
enabled: true
allow_single_line_rule_sets: false
SingleLinePerSelector:
enabled: true
MergeableSelector:
enabled: true
force_nesting: true
EmptyRule:
enabled: true