SCSS variables
In my career, I’ve managed to work on a lot of projects that used styling via SCSS, LESS, or Stylus. One of the main advantages of favoring them over CSS, besides “cascading”, was “variables”
They enabled:
To respect the DRY principle
To centralize shared variables for reuse via @import or @use
To create more abstract styles without hardcoding
To synchronize variable names with Figma tokens
To perform simple arithmetic and complex operations on variables
Variables did not go directly into the build, but were compiled into actual CSS values
Example of implementation
Let’s realize a basic example of SCSS variables
application
Variables
$primary: #d75894;
$secondary: #9b3dca;
$background: #fafafa;
Styling of elements
@use 'variables';
body {
background: variables.$background;
h1 {
color: variables.$primary;
}
p {
color: variables.$secondary;
}
}
It’s simple and intuitive *👍.*
New theme
But let’s say we need to add support for a dark theme for the current style scheme due to business requirements. *How do we implement it? *🧐
Experienced developers 🤓 will tell you that you should use mapping to substitute the correct value into the selector from each theme. In this way, we will provide extensibility for new themes.
Let’s change our simple variable list to a color theme map
$themes: (
"default": (
primary: #d75894,
secondary: #9b3dca,
background: #fafafa,
),
"dark": (
primary: #5e84ff,
secondary: #0dd0ff,
background: #1b1918,
)
);
Themes applying
@use "variables";
@use "sass:map";
@mixin setTheme($theme-map) {
background: map.get($theme-map, "background");
h1 {
color: map.get($theme-map, "primary")
}
p {
color: map.get($theme-map, "secondary")
}
}
body {
@each $theme-key in map.keys(variables.$themes) {
&[data-theme="#{$theme-key}"]{
@include setTheme(map.get(variables.$themes, $theme-key))
}
}
}
Result
Yay, we’ve achieved the requested behavior. But at what cost?
Problems
As you can see from this small example, the amount of code to support the new dark theme has increased, and the old scheme had to be refactored.
Another disadvantage is obtained is the increase in the resulting CSS file due to having multiple themes simultaneously.
And hence its size, which takes time 📉 to download and parse.
body[data-theme=default] {
background: #fafafa;
}
body[data-theme=default] h1 {
color: #d75894;
}
body[data-theme=default] p {
color: #9b3dca;
}
body[data-theme=dark] {
background: #1b1918;
}
body[data-theme=dark] h1 {
color: #5e84ff;
}
body[data-theme=dark] p {
color: #0dd0ff;
}
As a consequence, with the growth of the code base and the requirement for stylization, we will get:
Increasing complexity of style architecture in the development of individual components
Maintenance and development of new features will be harder every time
Constant refactoring and need for regression screen tests
These problems will undoubtedly affect the speed of development, the quality of the result, and the convenience of developers.
Unfortunately, many libraries developed using SCSS, such as @angular/material
, encourage this approach. Many developers are unaware of the recommended ways of styling via mixins, which leads to anti-pattern styling as well as the use of ::ng-deep
Those who have ever upgraded Angular in conjunction with
@angular/material
will understand UI problems in regression tests after upgrade if you don’t use the recommended way of component customization
So what’s the solution to this problem? read more...
Top comments (3)
That's not fair 😄
Maksim Dolgih,
Great article, very useful!
Thanks for sharing...
Great post! There are a couple issues in your markdown, especially around the italics and stuff…