dark mode

Use nested lists in Sass to organize CSS rules like padding and margin.

Use nested lists in Sass to organize CSS rules like padding and margin.

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:

  1. margin: 8px, 16px, 32px;
  2. margin-left: 8px, 16px, 32px;
  3. margin-right: 8px, 16px, 32px;
  4. margin-top: 8px, 16px, 32px;
  5. margin-Bottom: 8px, 16px, 32px;
  6. padding: 8px, 16px, 32px;
  7. padding-left: 8px, 16px, 32px;
  8. padding-right: 8px, 16px, 32px;
  9. padding-top: 8px, 16px, 32px;
  10. 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;
        }
      }
    }
  }
}

Related articles

© 2019 All rights reserved.