Create CSS Components with Variables and Nesting
CSS has come a long way since CSS pre-processors like LESS and SASS was made popular due to CSS’s limitations. One of the main use cases for CSS pre processors was the use of variables and nesting. Variables help us using the same value in different properties. Nesting allows us to write CSS rules that mimics the HTML DOM tree. These two combined are used primarily to transform a generic CSS styles into multiple specific ones, for example looping through a map of key-values pair to create multiple versions of the same component:
$badges:
"A" green lightgreen,
"B" darkgrey red,
"C" black orange;
@each $name, $fg, $bg in $icons {
.badge#{$name} {
margin-bottom: 2rem;
background-color: $bg;
border: 2px solid $fg;
border-radius: 8px;
.badgeTitle {
color: $fg;
width: 80%;
padding: 1rem;
font-weight: bold;
}
.info {
color: $fg;
padding: 0.5rem 1rem;
border-top: 1px solid $fg;
}
}
}
Previous code is compiled into this CSS code:
.badgeA {
margin-bottom: 2rem;
background-color: lightgreen;
border: 2px solid green;
border-radius: 8px;
}
.badgeA .badgeTitle {
color: green;
width: 80%;
padding: 1rem;
font-weight: bold;
}
.badgeA .info {
color: green;
padding: 0.5rem 1rem;
border-top: 1px solid green;
}
.badgeB {
margin-bottom: 2rem;
background-color: red;
border: 2px solid darkgrey;
border-radius: 8px;
}
.badgeB .badgeTitle {
color: darkgrey;
width: 80%;
padding: 1rem;
font-weight: bold;
}
.badgeB .info {
color: darkgrey;
padding: 0.5rem 1rem;
border-top: 1px solid darkgrey;
}
.badgeC {
margin-bottom: 2rem;
background-color: orange;
border: 2px solid black;
border-radius: 8px;
}
.badgeC .badgeTitle {
color: black;
width: 80%;
padding: 1rem;
font-weight: bold;
}
.badgeC .info {
color: black;
padding: 0.5rem 1rem;
border-top: 1px solid black;
}
As you can see, there are a lot of code repetition. We could reduce it by extracting out properties which are not dependent on the variables, however we would not see much reduction and it would be less readable. See here.
CSS variables and nesting are currently widely supported in modern browsers. This will greatly reduce the amount of CSS we write and serve through the network. In addition, it is much more readable as it mimics the HTML DOM and variables can be contained within its own block. The previous SCSS can be written purely in modern CSS:
.badgeContainer {
/* these are just defaults */
--fg: #000;
--bg: #fff;
color: var(--fg);
margin-bottom: 2rem;
background-color: var(--bg);
border: 2px solid var(--fg);
border-radius: 8px;
.badgeTitle {
width: 80%;
padding: 1rem;
font-weight: bold;
}
.badgeInfo {
padding: 0.5rem 1rem;
border-top: 1px solid var(--fg);
}
}
.badgeA {
--fg: green;
--bg: lightgreen;
}
.badgeB {
--fg: darkgrey;
--bg: red;
}
.badgeC {
--fg: black;
--bg: orange;
}
In the CSS code, we target all style rules for badges within .badgeContainer
. We declare the CSS variables that it is going to need within its component block and assigning them default values. These values are used via var()
within its own rules and its nested rules. These values can then be overridden in the specific badges.
We could think of the variables as inputs for the component definition and we declare the values of the inputs for each instance. See it in action in the demo below:
We could also use inline CSS to specify the CSS variables. See Badge D in the demo above.
CSS variables and nesting provide so much possibility in writing less CSS code while delivering more impact. What other use case can you think of with these features?