Wednesday, January 4, 2017

SASS - Handy Mixin to Handle Your Margins and Paddings

How many times have you found yourself in need to remove margin or a padding on your HTML element or to add extra 5 or 10 pixels to it?  I do that quite often, and if you are anything like me, you'll won't feel like you've done a good job if you just inline the style:

<div style="margin-left: 5px;">My awesome content</div>

Styles belong in the stylesheets, but how should you handle this particular situation? In the example, above I needed to add margin to the left, but what if I need to add margins on all sides? What if I need to add 10px instead of 5px?

A while ago I was expecting a website someone wrote and I saw this handy pattern of classes used throughout the website:

.m-0 { margin: 0; }
.m-5 { margin: 5px; }
.m-10 { margin: 10px; }
.m-t-0 { margin-top: 0; }
.m-t-5 { margin-top: 5px; }
.m-t-10 { margin-top: 10px; }
.m-r-0 { margin-right: 0; }
.m-r-5 { margin-right: 5px; }
.m-r-10 { margin-right: 10px; }
// ... and so on for all the sides and for paddings - you get the idea.

The first letter "m" or "p" stands for "margin" or "padding" respectfully. Second letter ("t", "r", "b", or "l") is the initial of the direction - "top", "right", "bottom", or "left". Finally, the number is the amount of pixel you want to use.

This is a fantastic set of helper classes. They are short, flexible, and provide a sense of standard - you are forced to use specific increments of spacing (5px, 10px...). When you need to modify spacing on an element you simply write something like this:

<div class="m-l-5 p-b-10">My awesome content</div>

The div in the example above will have margin-left: 5px and padding-bottom: 10px applied to it - clean and simple.

Now that you got the idea, you must be thinking:
"That's great, but my project will need classes for iterations of 4px, not 5px, and I'd like to be able to have classes available up to 16px. Writing all of the needed classes is kind of painful."
What a coincidence - I was thinking exactly the same thing! So I wrote a SASS Mixin to tackle this problem.

$step: 5;
$iterations: 4;

@mixin spaces-for-dir($dirs) {
  $d: "";
  @each $dir in $dirs {
    $d: $d + str-slice($dir, 1, 1);
  }
  $i: 0;
  $max: $step * $iterations;
  @while ($i <= $max) {
    .m-#{$d}-#{$i} {
      @each $dir in $dirs {
        margin-#{$dir}: $i*1px;
      }
    }
    .p-#{$d}-#{$i} {
      @each $dir in $dirs {
        padding-#{$dir}: $i*1px;
      }
    }
    $i: $i + $step;
  }
}

@mixin spaces-no-dir() {
  $i: 0;
  $max: $step * $iterations;
  @while ($i <= $max) {
    .m-#{$i} {
      margin: $i*1px;
    }
    .p-#{$i} {
      margin: $i*1px;
    }
    $i: $i + $step;
  }
}

Just copy the code above into a spaces.scss file in your project. Notice and modify two variables at the top. If you need iterations of 4px and have them go up to 16px, then set:

$step: 4;
$iterations: 4;

import the file into your project's main scss file and use this like so:

@include spaces-no-dir();
@include spaces-for-dir(top);
@include spaces-for-dir(right);
@include spaces-for-dir(bottom);
@include spaces-for-dir(left);

/*
@include spaces-for-dir(top right);
@include spaces-for-dir(top bottom);
@include spaces-for-dir(top left);
@include spaces-for-dir(right bottom);
@include spaces-for-dir(right left);
@include spaces-for-dir(bottom left);

@include spaces-for-dir(top right bottom);
@include spaces-for-dir(top right left);
@include spaces-for-dir(right bottom left);
*/

As you can see, the Mixin also handles multiple directions. Without uncommenting their use you'll get 2kb of pure joy! Maybe I get excited a bit too much for this. If you do uncomment multi-directional usages, the result will grow to a maximum of 8kb (which also is very little), but it'll allow you to write something like this:

<div class="p-rl-15">My awesome content</div>

This will apply padding-right: 15px and padding-left-15px to an element.

You can see and play with this Mixin here. Hope you found it useful.