Generate bootstrap like spacing classes using SASS
Tags: css, sass, webdev
Published: 2022-02-04 14:22:42

Last month we have initialized a new project with [Angular](https://angular.io/) and [Angular Material](https://material.angular.io/). As time goes, 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 components wherever needed.

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

Then I realized that we are actually missing bootstrap like margin and padding classes. One of my colleague suggested to use [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 an 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:

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

Where `sides` is one of:

- `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:

- `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`. 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 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 keys.
```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 `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 next two cases:

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`

Now we need to generate classes which can target specific side. 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 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 only left with following two cases to generate:

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`

To generate classes for `x` and `y` axises 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 presents in `$spacers` combining each axis presents 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 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.

```
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>
```

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](https://mazedulislam.com/)