It is easy to imagine a project with many helper classes for margins, paddings, colors, etc. With Sass you can organize data into nested lists, scale it easily and create all the CSS rules with loops. This way you can shorten your files at least three times. In the article I will guide you step-by-step how to loop through lists in Sass.
Many not appreciate fully Sass, but if you dig deeper, there are features that can reduce your code, make it scalable, maintainable and more readable.
Let’s say we need the following classes:
- margin: 8px, 16px, 32px;
- margin-left: 8px, 16px, 32px;
- margin-right: 8px, 16px, 32px;
- margin-top: 8px, 16px, 32px;
- margin-Bottom: 8px, 16px, 32px;
- padding: 8px, 16px, 32px;
- padding-left: 8px, 16px, 32px;
- padding-right: 8px, 16px, 32px;
- padding-top: 8px, 16px, 32px;
- padding-Bottom: 8px, 16px, 32px;
Here are 30 rules of CSS, every rule is a sum of 3 lines making 90 lines.
// example of the 3 lines rule
.margin {
margin: 8px;
}
Crazy right? There should be a better way to reduce the amount of styles and with Sass there is. From the example above we transform all data into list like this:
$spacings: (
'padding'
(
'': 8 16 32,
'left': 8 16 32,
'right': 8 16 32,
'top': 8 16 32,
'bottom': 8 16 32
),
'margin'
(
'': 8 16 32,
'left': 8 16 32,
'right': 8 16 32,
'top': 8 16 32,
'bottom': 8 16 32
)
);
This collection represents all 30 padding and margin rules that we need. This way it is easy to add additional units or to remove them.
First, we will just loop through the $spacings
list:
@each $type in $spacings {
.#{$type} {
}
}
What data will have $type
:
("": 8 16 32, "left": 8 16 32, "right": 8 16 32, "top": 8 16 32, "bottom": 8 16 32)
("": 8 16 32, "left": 8 16 32, "right": 8 16 32, "top": 8 16 32, "bottom": 8 16 32)
@each
will loop through the two keys padding
and margin
and will return their value.
We need to iterate over every key/value pair in a map. Sass support this with @each
and two variables, first is the key name, second is its value.
Now we can rewrite the loop like this:
@each $type, $sides in $spacings {
.#{$type} {
}
}
Now $type
contains padding
and margin
as strings and $sides
contains the two lines from above.
Now $type
contains padding
and margin
as strings and $sides
contains their values which are the two lines from above.
@each $type, $sides in $spacings {
@each $side, $values in $sides {
.#{$type}-#{$side} {
}
}
}
Now $side
contains a list of strings - left right top bottom
and $values
a list of 8 16 32
numbers.
To create rules with all the values from $values
we need one last loop:
@each $type, $sides in $spacings {
@each $side, $values in $sides {
@each $value in $values {
.#{$type}-#{$side} {
#{$type}-#{$side}: #{$value}px;
}
}
}
}
Now we are almost finished, we have all the rules created, but there is a little bug. When we set padding or margin to all sides, we have an unnecessary dash -
.
.padding- {
padding-: 8px;
}
.margin- {
margin-: 8px;
}
To fix that we need a @if @else
statement:
@each $type, $sides in $spacings {
@each $side, $values in $sides {
@each $value in $values {
@if #{$side} == '' {
.#{$type} {
#{$type}: #{$value}px;
}
} @else {
.#{$type}-#{$side} {
#{$type}-#{$side}: #{$value}px;
}
}
}
}
}
Working with nested lists or multidimensional arrays in Sass can save a lot of redundancies like in our case. Our final SCSS code is in just 34 lines while the formatted CSS will have 119 line. Benefits are not only in the difference of 85 lines, but in the better support.
Final code
$spacings: (
'padding'
(
'': 8 16 32,
'left': 8 16 32,
'right': 8 16 32,
'top': 8 16 32,
'bottom': 8 16 32
),
'margin'
(
'': 8 16 32,
'left': 8 16 32,
'right': 8 16 32,
'top': 8 16 32,
'bottom': 8 16 32
)
);
@each $type, $sides in $spacings {
@each $side, $values in $sides {
@each $value in $values {
@if #{$side} == '' {
.#{$type} {
#{$type}: #{$value}px;
}
} @else {
.#{$type}-#{$side} {
#{$type}-#{$side}: #{$value}px;
}
}
}
}
}