# Generate bootstrap-like spacing classes using SASS

### Motivation

Last month we initialized a new project with [Angular](https://angular.io/) and [Angular Material](https://material.angular.io/). As time goes on, I have noticed that some of my colleagues are often writing inline styles for margin and padding.

```html
<div style="margin-top: 5px; margin-bottom: 5px">
  With inline style
</div>
```

Some of them (including me) are creating similar CSS classes for almost every component wherever needed.

```css
.set-padding {
  padding: 10px 0;
}
.left-spacer {
  margin-left: 10px;
}
```

Then I realized that we are missing bootstrap-like margin and padding classes. One of my colleagues suggested using [Tailwind CSS](https://tailwindcss.com/). However, as we are already using Angular Material for our component library, installing a CSS framework only for some spacing classes will be overkill for sure. So, I decided to write these classes on my own.

### Bootstrap Classes: A Closer Look

According to the documentation of [Bootstrap 4](https://getbootstrap.com/docs/4.1/utilities/spacing/) its spacing classes have the following format:

The classes are named using the format `{property}{sides}-{size}` for `xs` and `{property}{sides}-{breakpoint}-{size}` for `sm`, `md`, `lg`, and `xl`.

Where `property` is one of the:

* `m` - for classes that set `margin`
    
* `p` - for classes that set `padding`
    

Where `sides` is one of the:

* `t` - for classes that set `margin-top` or `padding-top`
    
* `b` - for classes that set `margin-bottom` or `padding-bottom`
    
* `l` - for classes that set `margin-left` or `padding-left`
    
* `r` - for classes that set `margin-right` or `padding-right`
    
* `x` - for classes that set both `*-left` and `*-right`
    
* `y` - for classes that set both `*-top` and `*-bottom`
    
* blank - for classes that set a `margin` or `padding` on all 4 sides of the element
    

Where `size` is one of the:

* `0` - for classes that eliminate the `margin` or `padding` by setting it to `0`
    
* `1` - (by default) for classes that set the `margin` or `padding` to `$spacer * .25`
    
* `2` - (by default) for classes that set the `margin` or `padding` to `$spacer * .5`
    
* `3` - (by default) for classes that set the `margin` or `padding` to `$spacer`
    
* `4` - (by default) for classes that set the `margin` or `padding` to `$spacer * 1.5`
    
* `5` - (by default) for classes that set the `margin` or `padding` to `$spacer * 3`
    
* `auto` - for classes that set the `margin` to auto
    

### Define Our Requirements

Our focus is to generate all the CSS classes of the format `{property}{sides}-{size}`.

For example:

1. `m-0` to `m-5` and `m-auto`
    
2. `p-0` to `p-5`
    
3. `mt-0`, `mb-0`, `ml-0`, `mr-0` to `mt-5`, `mb-5`, `ml-5`, `mr-5` and `mt-auto`, `mb-auto`, `ml-auto`, `mr-auto`
    
4. `pt-0`, `pb-0`, `pl-0`, `pr-0` to `pt-5`, `pb-5`, `pl-5`, `pr-5`
    
5. `mx-0` to `mx-5` and `my-0` to `my-5` and `mx-auto`, `my-auto`
    
6. `px-0` to `px-5` and `py-0` to `my-5`
    

Notice, we are omitting `{property}{sides}-{breakpoint}-{size}` pattern, which is not in the scope of this article.

### SASS Implementation

I am going to use [SCSS](https://sass-lang.com/documentation/syntax#scss) syntax, you can also use the original [SASS](https://sass-lang.com/documentation/syntax#the-indented-syntax) if you find that easier to use.

Let's create a new file `_spaces.scss`. The filename starts with `_` because I want to make it a partial sass file. You can check the [Sass guide](https://sass-lang.com/guide) if you do not know what a partial Sass file means.

Create a variable `$spacer` with the default value for space.

```scss
// _spaces.scss
$spacer: 1rem !default;
```

Then create a [`sass:map`](https://sass-lang.com/documentation/modules/map) with keys from `0` to `5` and `auto` and set the calculated value for each key.

```scss
$spacers: (
  0: 0,
  1: $spacer * 0.25,
  2: $spacer * 0.5,
  3: $spacer,
  4: $spacer * 1.5,
  5: $spacer * 3,
  auto: auto,
) !default;
```

Now, let's loop through the map and generate classes from `m-0` to `m-5` and `m-auto`.

```scss
@each $key, $value in $spacers {
  // generate m-* classes
  .m-#{$key} {
    margin: #{$value} !important;
  }
}
```

We can also generate padding classes inside this loop. Let's generate classes from `p-0` to `p-5`.

```scss
@each $key, $value in $spacers {
  // generate m-* classes
  .m-#{$key} {
    margin: #{$value} !important;
  }

  // generate p-* classes
  .p-#{$key} {
    padding: #{$value} !important;
  }
}
```

However, this code will also generate `.p-auto { padding: auto !important; }` which is incorrect. So, we need to exclude the `auto` key when generating `.p-*` classes.

```scss
@each $key, $value in $spacers {
  // generate m-* classes
  .m-#{$key} {
    margin: #{$value} !important;
  }

  // generate p-* classes excluding key = auto
  @if $key != auto {
    .p-#{$key} {
      padding: #{$value} !important;
    }
  }
}
```

Till now, we have covered the following cases:

1. `m-0` to `m-5` and `m-auto`
    
2. `p-0` to `p-5`
    

Let's focus on the next two cases:

1. `mt-0`, `mb-0`, `ml-0`, `mr-0` to `mt-5`, `mb-5`, `ml-5`, `mr-5` and `mt-auto`, `mb-auto`, `ml-auto`, `mr-auto`
    
2. `pt-0`, `pb-0`, `pl-0`, `pr-0` to `pt-5`, `pb-5`, `pl-5`, `pr-5`
    

Now we need to generate classes that can target specific sides. Therefore create a [`sass:list`](https://sass-lang.com/documentation/modules/list) containing all the sides.

```scss
$sides: (top, bottom, left, right);
```

For each key presents in the `$spacers` map we need to generate classes combining each direction/side. Therefore, we need a nested loop like this.

```scss
@each $key, $value in $spacers {
  @each $side in $sides {
    // generate m* classes
    .m#{str-slice($side, 0, 1)}-#{$key} {
      margin-#{$side}: #{$value} !important;
    }
  }
}
```

Same as before, we can generate padding classes (excluding `auto` key) inside this loop.

```scss
@each $key, $value in $spacers {
  @each $side in $sides {
    // generate m* classes
    .m#{str-slice($side, 0, 1)}-#{$key} {
      margin-#{$side}: #{$value} !important;
    }

    // generate p* classes excluding key = auto
    @if $key != auto {
      .p#{str-slice($side, 0, 1)}-#{$key} {
        padding-#{$side}: #{$value} !important;
      }
    }
  }
}
```

Now we are only left with the following two cases to generate:

1. `mx-0` to `mx-5` and `my-0` to `my-5` and `mx-auto`, `my-auto`
    
2. `px-0` to `px-5` and `py-0` to `my-5`
    

To generate classes for `x` and `y` axes let's create a new [`sass:list`](https://sass-lang.com/documentation/modules/list).

```scss
$axises: (x, y);
```

Same as before, for each key value present in `$spacers` combining each axis present in `$axis` list we need to generate classes. So, we need to use nested loops again.

```scss
@each $key, $value in $spacers {
  @each $axis in $axises {
    @if $axis == x {
      // generate classes for x axis

      // generate mx-* classes
      .m#{$axis}-#{$key} {
        margin-left: #{$value} !important;
        margin-right: #{$value} !important;
      }

      // generate px-* classes excluding key = auto
      @if $key != auto {
        .p#{$axis}-#{$key} {
          padding-left: #{$value} !important;
          padding-right: #{$value} !important;
        }
      }
    } @else if $axis == y {
      // generate classes for y axis

      // generate my-* classes
      .m#{$axis}-#{$key} {
        margin-top: #{$value} !important;
        margin-bottom: #{$value} !important;
      }

      // generate py-* classes excluding key = auto
      @if $key != auto {
        .p#{$axis}-#{$key} {
          padding-top: #{$value} !important;
          padding-bottom: #{$value} !important;
        }
      }
    } @else {
      @error "Unknown axis #{$axis}.";
    }
  }
}
```

### Usage

If your project setup supports a Scss file, then you can import this file into your root style file using [`@use`](https://sass-lang.com/documentation/at-rules/use) rule.

```scss
// styles.scss file, in the same directory of _spaces.scss
@use "./spaces";
```

If you need compiled css, then you can install [SASS](https://sass-lang.com/guide) on your machine and use the following command to generate `spaces.css` file.

```bash
sass _spaces.scss spaces.css
```

After adding this, now we can use bootstrap-like CSS classes in our HTML code.

```html
<div class="my-2 px-2">
  Styled with bootstrap like classes!
</div>
```

### Conclusion

The complete source code is available [here](https://github.com/mazid1/bs-spacing/blob/main/src/_spacing.scss).

---

Thank you for reading. Your appreciation is my motivation!

Follow me on social media:

* Linkedin: [mazedul-islam](https://www.linkedin.com/in/mazedul-islam/)
    
* Twitter: [@mazedul\_\_islam](https://twitter.com/mazedul__islam)
    
* Github: [mazid1](https://github.com/mazid1)
    
* Website: [mazedulislam.com](http://mazedulislam.com)
    

---

I'm open for a remote full-time/contract/freelance job for the position of Full-stack Software Engineer. If you are hiring, ping me at [mazidmailbox@gmail.com](http://mailto:mazidmailbox@gmail.com)
