Where to Discuss?

Local Group

Preface

Goal: Generate custom spacing classes step by step, utilizing sass loop capability.

Even when utilizing CSS Framework, theme making require to create custom CSS. One of my need is spacing class, that is not available in neither Bulma nor Materialize. This spacing class can be made utilizing SASS.

SCSS: script

These guidance will save you a lot of coding time. And also tons of typing.

Reading

Basic Loop:

Most code below is inspired by:

Another reading:

CSS Preprocessor

SASS/SCSS is one alternative among CSS preprocessor family.

Illustration: CSS Preprocessor


1: @for

Imagine that we need a sequence of classes to handle margin, similar like CSS below:

.m-1 {
  margin: 1px;
}

This can be achieved with this loop constructor

@for ... from ... through ... {
  ...
}

CSS Class Naming

We want to achieve this class naming

  • .m-#{$number}

SASS Source

For comfort reason, we also need to define intial value for the loop.

// variable initialization

$loop-begin: 1 !default;
$loop-stop:  3 !default;

// loop

@for $cursor from $loop-begin through $loop-stop {
  .m-#{$cursor} {
    margin: #{$cursor}px;
  }
}

Variable Interpolation

Inside the loop we have this #{…} code. This is variable interpolation.

We use variable interpolation, when we want to extract value into the css.

CSS Result

The #{$cursor} variable takes care the rest, so now we have this result below:

.m-1 {
  margin: 1px;
}

.m-2 {
  margin: 2px;
}

.m-3 {
  margin: 3px;
}

Limitation

The issue with @for is we cannot use interval. We can have this [1, 2, 3, 4, 5] sequence. But we cannot have this [5, 10, 15, 20, 25] sequence.


2: @while

To solve [5, 10, 15, 20, 25] sequence, we can utilize @while.

$cursor: $loop-begin;

@while $cursor <= $loop-end {
  ...

  $cursor: $cursor + $interval;
}

CSS Class Naming

We still want to achieve this class naming

  • .m-#{$number}

SASS Source

Consider this @while loop below:

// variable initialization
$loop-begin:  5 !default;
$loop-end:   25 !default;
$interval:    5 !default;

// loop
$cursor: $loop-begin;

@while $cursor <= $loop-end {
  .m-#{$cursor} {
    margin: #{$cursor}px;
  }

  $cursor: $cursor + $interval;
}

CSS Result

.m-5 {
  margin: 5px;
}

.m-10 {
  margin: 10px;
}

.m-15 {
  margin: 15px;
}

.m-20 {
  margin: 20px;
}

.m-25 {
  margin: 25px;
}

3: @each

Before facing complex situation, consider a simple example.

Challenge

Now we have challenge that margin property has these variants:

  • margin,

  • margin-top,

  • margin-bottom,

  • margin-left,

  • margin-right

For simplicity reason, I exclude the original margin variant.

CSS Class Naming

We want to achieve this class naming

  • .m-#{$side}-5

List Declaration

Sass variable can handle a list.

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

Accessing List

This list can be accessed by using @each iterator.

@each ... in ... {
  ...
}

SASS Source

Consider accessing $sides by this example below:

// property
$sides: (top, bottom, left, right);

@each $side in $sides {
  .m-#{$side}-5 {
    margin-#{$side}: 5px;
  }
}

CSS Result

Now we have this:

.m-top-5 {
  margin-top: 5px;
}

.m-bottom-5 {
  margin-bottom: 5px;
}

.m-left-5 {
  margin-left: 5px;
}

.m-right-5 {
  margin-right: 5px;
}

This is ugly, because we want .m-t-5, instead of .m-top-5.


4: @each with Pairs

Sass has solution for this issue.

CSS Class Naming

We want to achieve this class naming

  • .m-#{$abbreviation}-5

List Declaration

Luckily, sass allow us to have pairs in list. Now we have CSS sub-property as below:

$sides: (top: t, bottom: b, left: l, right: r);

SASS Source

Consider rewrite previous code.

// property: abbreviation
$sides: (top: t, bottom: b, left: l, right: r);

@each $side, $name in $sides {
  .m-#{$name}-5 {
    margin-#{$side}: 5px;
  }
}

CSS Result

Now we have what wee need.

.m-t-5 {
  margin-top: 5px;
}

.m-b-5 {
  margin-bottom: 5px;
}

.m-l-5 {
  margin-left: 5px;
}

.m-r-5 {
  margin-right: 5px;
}

Notice that I use .m-t-5, instead of .mt-5, to differ from bootstrap spacing classes.


5: @each in @while

Consider leverage to a more complex situation. We need a sequence of each classes.

CSS Class Naming

We want to achieve this class naming

  • .m-#{$subname}-#{$number}

Skeleton

We put @each iterator inside @while loop.

@while $cursor <= $loop-end {

  @each $side, $name in $sides {
    ...
  }

  $cursor: $cursor + $interval;
}

SASS Source

// variable initialization
$loop-begin:  5 !default;
$loop-end:   25 !default;
$interval:    5 !default;

// sub-property: abbreviation
$sides: (top: t, bottom: b, left: l, right: r);

// loop
$cursor: $loop-begin;

@while $cursor <= $loop-end {

  @each $side, $name in $sides {
    .m-#{$name}-#{$cursor} {
      margin-#{$side}: #{$cursor}px;
    }
  }

  $cursor: $cursor + $interval;
}

CSS Result

.m-t-5 {
  margin-top: 5px;
}

.m-b-5 {
  margin-bottom: 5px;
}

.m-l-5 {
  margin-left: 5px;
}

.m-r-5 {
  margin-right: 5px;
}

.m-t-10 {
  margin-top: 10px;
}

.m-b-10 {
  margin-bottom: 10px;
}

.m-l-10 {
  margin-left: 10px;
}

.m-r-10 {
  margin-right: 10px;
}

.m-t-15 {
  margin-top: 15px;
}

.m-b-15 {
  margin-bottom: 15px;
}

.m-l-15 {
  margin-left: 15px;
}

.m-r-15 {
  margin-right: 15px;
}

.m-t-20 {
  margin-top: 20px;
}

.m-b-20 {
  margin-bottom: 20px;
}

.m-l-20 {
  margin-left: 20px;
}

.m-r-20 {
  margin-right: 20px;
}

.m-t-25 {
  margin-top: 25px;
}

.m-b-25 {
  margin-bottom: 25px;
}

.m-l-25 {
  margin-left: 25px;
}

.m-r-25 {
  margin-right: 25px;
}

6: Nested @while

CSS Class Naming

We want to achieve this class naming

  • .#{$name}-#{$subname}-#{$number}

List Declaration

We define CSS property list:

  • property: margin and padding

  • each has sub-property: top, bottom, left, right.

$sides: (top: t, bottom: b, left: l, right: r);
$properties: (margin: m, padding: p);

Skeleton

We put both @each iterator, inside @while loop.

@while $cursor <= $loop-end {

  @each $prop, $name in $properties {
    @each $side, $subname in $sides {
      ...
    }
  }
  $cursor: $cursor + $interval;
}

SASS Source

// variable initialization
$loop-begin:  5 !default;
$loop-end:   25 !default;
$interval:    5 !default;

// sub-property: abbreviation
$sides: (top: t, bottom: b, left: l, right: r);
$properties: (margin: m, padding: p);

// loop
$cursor: $loop-begin;

@while $cursor <= $loop-end {
  @each $prop, $name in $properties {
    @each $side, $subname in $sides {
      .#{$name}-#{$subname}-#{$cursor} {
        #{$prop}-#{$side}: #{$cursor}px;
      }
    }
  }

  $cursor: $cursor + $interval;
}

CSS Result

Now we have both margin and padding.

.m-t-5 {
  margin-top: 5px;
}

.m-b-5 {
  margin-bottom: 5px;
}

.m-l-5 {
  margin-left: 5px;
}

.m-r-5 {
  margin-right: 5px;
}

.p-t-5 {
  padding-top: 5px;
}

.p-b-5 {
  padding-bottom: 5px;
}

.p-l-5 {
  padding-left: 5px;
}

.p-r-5 {
  padding-right: 5px;
}

.m-t-10 {
  margin-top: 10px;
}

.m-b-10 {
  margin-bottom: 10px;
}

.m-l-10 {
  margin-left: 10px;
}

.m-r-10 {
  margin-right: 10px;
}

.p-t-10 {
  padding-top: 10px;
}

.p-b-10 {
  padding-bottom: 10px;
}

.p-l-10 {
  padding-left: 10px;
}

.p-r-10 {
  padding-right: 10px;
}

.m-t-15 {
  margin-top: 15px;
}

.m-b-15 {
  margin-bottom: 15px;
}

.m-l-15 {
  margin-left: 15px;
}

.m-r-15 {
  margin-right: 15px;
}

.p-t-15 {
  padding-top: 15px;
}

.p-b-15 {
  padding-bottom: 15px;
}

.p-l-15 {
  padding-left: 15px;
}

.p-r-15 {
  padding-right: 15px;
}

.m-t-20 {
  margin-top: 20px;
}

.m-b-20 {
  margin-bottom: 20px;
}

.m-l-20 {
  margin-left: 20px;
}

.m-r-20 {
  margin-right: 20px;
}

.p-t-20 {
  padding-top: 20px;
}

.p-b-20 {
  padding-bottom: 20px;
}

.p-l-20 {
  padding-left: 20px;
}

.p-r-20 {
  padding-right: 20px;
}

.m-t-25 {
  margin-top: 25px;
}

.m-b-25 {
  margin-bottom: 25px;
}

.m-l-25 {
  margin-left: 25px;
}

.m-r-25 {
  margin-right: 25px;
}

.p-t-25 {
  padding-top: 25px;
}

.p-b-25 {
  padding-bottom: 25px;
}

.p-l-25 {
  padding-left: 25px;
}

.p-r-25 {
  padding-right: 25px;
}

7: Final

Now comes the final result.

CSS Class Naming

We want to achieve both class naming

  • .#{$name}-#{$number}

  • .#{$name}-#{$subname}-#{$number}

Skeleton

We put both @each iterator, inside @while loop.

@while $cursor <= $loop-end {

  @each $prop, $name in $properties {
    ...

    @each $side, $subname in $sides {
      ...
    }
  }
  
  $cursor: $cursor + $interval;
}

SASS Source

// variable initialization
$loop-begin:  5 !default;
$loop-end:   25 !default;
$interval:    5 !default;

// sub-property: abbreviation
$sides: (top: t, bottom: b, left: l, right: r);
$properties: (margin: m, padding: p);

// loop
$cursor: $loop-begin;

@while $cursor <= $loop-end {
  @each $prop, $name in $properties {
    .#{$name}-#{$cursor} {
      #{$prop}: #{$cursor}px !important;
    }

    @each $side, $subname in $sides {
      .#{$name}-#{$subname}-#{$cursor} {
        #{$prop}-#{$side}: #{$cursor}px !important;
      }
    }
  }

  $cursor: $cursor + $interval;
}

Notice that I also put !important in css value.

CSS Result

.m-5 {
  margin: 5px !important;
}

.m-t-5 {
  margin-top: 5px !important;
}

.m-b-5 {
  margin-bottom: 5px !important;
}

.m-l-5 {
  margin-left: 5px !important;
}

.m-r-5 {
  margin-right: 5px !important;
}

.p-5 {
  padding: 5px !important;
}

.p-t-5 {
  padding-top: 5px !important;
}

.p-b-5 {
  padding-bottom: 5px !important;
}

.p-l-5 {
  padding-left: 5px !important;
}

.p-r-5 {
  padding-right: 5px !important;
}

.m-10 {
  margin: 10px !important;
}

.m-t-10 {
  margin-top: 10px !important;
}

.m-b-10 {
  margin-bottom: 10px !important;
}

.m-l-10 {
  margin-left: 10px !important;
}

.m-r-10 {
  margin-right: 10px !important;
}

.p-10 {
  padding: 10px !important;
}

.p-t-10 {
  padding-top: 10px !important;
}

.p-b-10 {
  padding-bottom: 10px !important;
}

.p-l-10 {
  padding-left: 10px !important;
}

.p-r-10 {
  padding-right: 10px !important;
}

.m-15 {
  margin: 15px !important;
}

.m-t-15 {
  margin-top: 15px !important;
}

.m-b-15 {
  margin-bottom: 15px !important;
}

.m-l-15 {
  margin-left: 15px !important;
}

.m-r-15 {
  margin-right: 15px !important;
}

.p-15 {
  padding: 15px !important;
}

.p-t-15 {
  padding-top: 15px !important;
}

.p-b-15 {
  padding-bottom: 15px !important;
}

.p-l-15 {
  padding-left: 15px !important;
}

.p-r-15 {
  padding-right: 15px !important;
}

.m-20 {
  margin: 20px !important;
}

.m-t-20 {
  margin-top: 20px !important;
}

.m-b-20 {
  margin-bottom: 20px !important;
}

.m-l-20 {
  margin-left: 20px !important;
}

.m-r-20 {
  margin-right: 20px !important;
}

.p-20 {
  padding: 20px !important;
}

.p-t-20 {
  padding-top: 20px !important;
}

.p-b-20 {
  padding-bottom: 20px !important;
}

.p-l-20 {
  padding-left: 20px !important;
}

.p-r-20 {
  padding-right: 20px !important;
}

.m-25 {
  margin: 25px !important;
}

.m-t-25 {
  margin-top: 25px !important;
}

.m-b-25 {
  margin-bottom: 25px !important;
}

.m-l-25 {
  margin-left: 25px !important;
}

.m-r-25 {
  margin-right: 25px !important;
}

.p-25 {
  padding: 25px !important;
}

.p-t-25 {
  padding-top: 25px !important;
}

.p-b-25 {
  padding-bottom: 25px !important;
}

.p-l-25 {
  padding-left: 25px !important;
}

.p-r-25 {
  padding-right: 25px !important;
}

Now you can use this spacing sass in your project.


8: Update: XY

For practical reason, I have to update this article.

  • Using .sass instead of .scss.

  • Start form zero .0, instead of 5.

  • Consider X, and Y just like bootstrap.

.m-y-5 {
  margin-top: 5px !important;
  margin-bottom: 5px !important;
}

.m-x-5 {
  margin-left: 5px !important;
  margin-right: 5px !important;
}

The drawback is, I have bigger stylesheet size.

List Declaration

Luckily, sass allow us to have pairs in list. Now we have CSS sub-property as below:

$sides:  (top: t, bottom: b, left: l, right: r)
$sidesy: (top, bottom)
$sidesx: (left, right)
$properties: (margin: m, padding: p)

And the loop is a little bit different:

// loop
$cursor: $loop-begin

@while $cursor <= $loop-end
  @each $prop, $name in $properties

    .#{$name}-y-#{$cursor}
      @each $side in $sidesy
        #{$prop}-#{$side}: #{$cursor}px !important

    .#{$name}-x-#{$cursor}
      @each $side in $sidesx
        #{$prop}-#{$side}: #{$cursor}px !important

  $cursor: $cursor + $interval

SASS Source

// variable initialization
$loop-begin:  0 !default
$loop-end:   25 !default
$interval:    5 !default

// sub-property: abbreviation
$sides:  (top: t, bottom: b, left: l, right: r)
$sidesy: (top, bottom)
$sidesx: (left, right)
$properties: (margin: m, padding: p)

// loop
$cursor: $loop-begin

@while $cursor <= $loop-end
  @each $prop, $name in $properties
    .#{$name}-#{$cursor}
      #{$prop}: #{$cursor}px !important

    @each $side, $subname in $sides
      .#{$name}-#{$subname}-#{$cursor}
        #{$prop}-#{$side}: #{$cursor}px !important

    .#{$name}-y-#{$cursor}
      @each $side in $sidesy
        #{$prop}-#{$side}: #{$cursor}px !important

    .#{$name}-x-#{$cursor}
      @each $side in $sidesx
        #{$prop}-#{$side}: #{$cursor}px !important

  $cursor: $cursor + $interval

Conclusion

These spacing classes is ready to serve.

SCSS: output

What do you think ?