Creating a style utility file with some SCSS magic ✨
Tags: scss, css, styles, webdev
Published: 2021-09-26 02:49:31

You might have used style frameworks in the past like *Bootstrap* or *Bulma*. Most of these types of libraries provide **utility** classes you can easily use in your HTML layouts, such as `ml-10` for left margin, or `pr-5` for right padding. One way of doing this is with a super long file and repetitive class declarations. Not very readable or scalable though is it?

In this article, we'll dive into **making our own utility style file with scss**, using some cool scss magic you might not have used before. In our example we'll be working with `margin`, but you could easily reproduce with any properties you like! The way we do this is flexible -- you provide the values for your classes (instead of mapping 1-100 for example).

&nbsp;
## Let's make a new `.scss` file

Pretty easy. I'll let you decide on how you want to do this. 

*Tip: you can structure your scss files similarly to JS files and make it super readable! I love using index.scss files to group imports within a folder, then having the parent import the index file.*

&nbsp;
## Let's set up some variables

We're going to need 4 variables (a couple are optional):

`auto` (optional) - good practice to extract constants to variables. This is used to hold the auto value.

`directions` - an array of strings, to cover the 4 different directions our margin could be (top, bottom, left, right)

`css-property-map` (optional) - A scss map to map our directions above to CSS properties. SCSS maps work similarly to JS, with a key/value.  *I use this because I want my utility classes to be shorthand/small in size. You could avoid this by having the full direction in your class.*

`sizes`: an array of CSS values. These are the utility classes/values we want to generate. I've also included an `auto` value which gets handled separately as it's not a standard `px` value.

```css
$auto: auto;
$directions: 't', 'b', 'l', 'r';
$css-property-map: ('t': margin-top, 'b': margin-bottom, 'l': margin-left, 'r': margin-right);
$sizes: 0, 5, 10, 20, 30, 40, 50, 60, 100, $auto;
```

&nbsp;
## And now some loops

We set up a couple of dynamic loops (think `for each` loop in JS). This will give us all sizes for each direction.

```css
@each $direction in $directions {
  @each $size in $sizes {
    // Classes coming here
  }
}
```

&nbsp;
## Generate the actual utility class

We dynamically create CSS classes for each direction/size combo. This will give us the classes in a `.ml-5` format.

```css
@each $direction in $directions {
  @each $size in $sizes {
    .m#{$direction}-#{$size} {
      // CSS property/values coming here
    }
  }
}
```

&nbsp;
## Setup the CSS properties and values

We compare the size to our previously defined `auto` value. If it's `auto`, we don't need to build a `px` value.

`#{map-get($css-property-map, $direction)}` let's us build dynamic CSS properties. Let's deep dive into what each bit means:

- `#{}` - inject an SCSS variable into CSS

- `map-get(map, key)` - pull out a value from a specific map with the passed key

```css
@if $size == $auto {
  #{map-get($css-property-map, $direction)}: $auto;
} @else {
  #{map-get($css-property-map, $direction)}: #{$size}px;
}
```

&nbsp;
## Complete util code

```css
$auto: auto;
$directions: 't', 'b', 'l', 'r';
$css-property-map: ('t': margin-top, 'b': margin-bottom, 'l': margin-left, 'r': margin-right);
$sizes: 0, 5, 10, 20, 30, 40, 50, 60, 100, $auto;

@each $direction in $directions {
  @each $size in $sizes {
    .m#{$direction}-#{$size} {
      @if $size == $auto {
        #{map-get($css-property-map, $direction)}: $auto;
      } @else {
        #{map-get($css-property-map, $direction)}: #{$size}px;
      }
    }
  }
}
```

&nbsp;
### And that's it! We've now dynamically generated a collection of top/bottom/left/right margin classes.