Fast color helpers with SASS Lists

Yep, it’s that time of the week again. Time for more insanely optimized helper classes in SASS.

Let’s talk about colors. So, say you have a list of color variables:

1
2
3
4
5
6
7
8
$blue:      #0ab0ed;
$blue-dark: #0064cd;
$green:     #8da1ae;
$red:       #f06338;
$yellow:    #e7dfb1;
$orange:    #f89406;
$pink:      #c3325f;
$purple:    #7a43b6;

You probably want some helper classes to pepper through your code, like .color-blue or .bg-blue. Fortunately, with SASS lists, this process is almost as easy as typing out the variables in the first place.

Set up a list:
variables_and_overrides.scss
1
2
3
4
5
6
7
8
9
10
$colors: (
  $blue blue,
  $blue-dark blue-dark,
  $green green,
  $red red,
  $yellow yellow,
  $orange orange,
  $pink pink,
  $purple purple
  );

Simple enough, right? Okay, now let’s set up our mixins.

Set up some mixins using interpolation and nth:
variables_and_overrides.scss
1
2
3
4
5
6
7
8
9
10
11
12
13
@mixin generate-colors() {
  @each $color in $colors {
    .color-#{nth($color, 2)} {
      color: nth($color, 1);
    }
    .bg-#{nth($color, 2)} {
      background: nth($color, 1);
    }
    .border-#{nth($color, 2)} {
      border-color: nth($color, 1);
    }
  }
}
Call your mixin:
variables_and_overrides.scss
1
@include generate-colors();
Lust at the beautiful helpers at your fingertips:
application.css
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
.color-blue {
  color: #0ab0ed; }

.bg-blue {
  background: #0ab0ed; }

.border-blue {
  border-color: #0ab0ed; }

.color-blue-dark {
  color: #0064cd; }

.bg-blue-dark {
  background: #0064cd; }

.border-blue-dark {
  border-color: #0064cd; }

.color-green {
  color: #8da1ae; }

.bg-green {
  background: #8da1ae; }

.border-green {
  border-color: #8da1ae; }

.color-red {
  color: #f06338; }
...
Side note on speed:

If you aren’t using it yet, I really encourage you to start using gulp-sass, which is built ontop of node-sass right now.

File saves are often under 200ms, which is practically instant; and you can get away with doing some pretty insane loops and code generation really quickly and easily. I’m working on a few Rails projects and plan on continuing to use this process instead of the native Rails SASS simply because the speed is extraordinary.

Soft Injecting CSS

This task has been changed. It’s now called grunt-browser-sync.

I am a big fan (if you haven’t noticed in my prior posts) of optimizing my workflow. One thing I’ve never found until recently was a solid way to deal with styles and a live workflow. In comes grunt-style-injector.

The task is simple.

gruntfile.coffee
1
2
3
4
5
6
styleinjector:
  files:
    src: 'css/application.css'
    options:
      watchTask: false
      debugInfo: true

You simply type in:

1
2
3
4
5
6
7
8
9
⇒ grunt styleinjector
Running "styleinjector:files" (styleinjector) task
   info  - socket.io started


All Set Up! Now copy & paste this snippet just before the closing </body> tag in your website.

<script src='http://192.168.1.113:3000/socket.io/socket.io.js'></script>
<script src='http://192.168.1.113:3001/style-injector-client.min.js'></script>

Put those snippets in your index.html (or partial of choice) and make sure you don’t commit said file, and you’re good to go. Since it’s framework agnostic, you can use whatever compilation process you want, and it never falsely reloads CSS (something I found) happened all the time with LiveReload.

Loops and Mixins in SASS and Stylus

Check out how easy this is to do with Stylus; added instructions and example at the end of this post.

The beauty of freelancing is twofold: you work on a lot of different projects simultaneously, and have to learn to quickly dive into a various set of systems at any given moment.

One challenge I run into in my work is building scalable, modular CSS, and lately I’ve been making a strong effort to write more modular code.

Here’s a pattern I ran into today. Say I want to add a simple spacer class that adds a little padding or margin on an element. I’d rather not have to do anything beyond editing the HTML markup, so let’s generate some CSS classes using a SASS @each loop.

My first take was to set up some $spaceamounts, then generate a few mixins:

helpers.scss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
$spaceamounts: (5, 10, 15, 20, 25, 30);

@mixin generate-margin-bottom() {
  @each $space in $spaceamounts {
    .mb-#{$space} {
      margin-bottom: #{$space}px;
    }
  }
}
@mixin generate-margin-right() {
  @each $space in $spaceamounts {
    .mr-#{$space} {
      margin-right: #{$space}px;
    }
  }
}
@mixin generate-margin-top() {
  @each $space in $spaceamounts {
    .mt-#{$space} {
      margin-top: #{$space}px;
    }
  }
}
@mixin generate-padding-top() {
  @each $space in $spaceamounts {
    .pt-#{$space} {
      padding-top: #{$space}px;
    }
  }
}
@mixin generate-padding-bottom() {
  @each $space in $spaceamounts {
    .pb-#{$space} {
      padding-bottom: #{$space}px;
    }
  }
}

@include generate-margin-bottom();
@include generate-margin-right();
@include generate-margin-top();
@include generate-padding-bottom();
@include generate-padding-top();

This approach definitely works. I get some sensibly generated CSS:

application.css
1
2
3
4
5
6
7
8
9
10
11
.ml-5 {
  margin-left: 5px; }

.ml-10 {
  margin-left: 10px; }

.ml-15 {
  margin-left: 15px; }

...

But, that’s a lot of copying and pasting. How about optimizing a bit?

With the relatively new @each loop and nested array functions in SASS, you can set comma delimited lists for use in dynamic variables.

helpers.scss
1
2
3
4
5
// let's generate some CSS!
// loops through array:
// vars: amt, direction, class-suffix
$default-space-amounts-with-direction: (5 left l, 10 left l, 15 left l, 25 left l, 30 left l);

We set up a basic iteration loop, here. The goal is to generate markup that follows our pattern from above, which fortunately is fairly simple:

helpers.scss
1
2
3
4
5
6
7
8
9
10
11
12
@mixin generate-spacing-classes(
  $default-space-amounts-with-direction: (5 left l, 10 left l, 15 left l, 25 left l, 30 left l)
) {
  @each $space in $default-space-amounts-with-direction {
    .m#{nth($space, 3)}-#{nth($space, 1)} {
      margin-#{nth($space, 2)}: #{nth($space, 1)}px;
    }
  }
}

@include generate-spacing-classes();

This generates the exact same markup as before.

Boom. Now, I can add more variable array definitions and simply include a few lines to have it output for each of these loops:

helpers.scss
1
2
3
4
5
6
7
8
9
$right-space-vars: (5 right r, 10 right r, 15 right r, 25 right r, 30 right r);
$bottom-space-vars: (5 bottom b, 10 bottom b, 15 bottom b, 25 bottom b, 30 bottom b);
$top-space-vars: (5 top t, 10 top t, 15 top t, 25 top t, 30 top t);

@include generate-spacing-classes(); // left comes by default
@include generate-spacing-classes($right-space-vars);
@include generate-spacing-classes($bottom-space-vars);
@include generate-spacing-classes($top-space-vars);

Voila, we get this:

application.css
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
.ml-5 {
  margin-left: 5px; }

.ml-10 {
  margin-left: 10px; }

.ml-15 {
  margin-left: 15px; }

.ml-25 {
  margin-left: 25px; }

.ml-30 {
  margin-left: 30px; }

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

.mr-10 {
  margin-right: 10px; }

.mr-15 {
  margin-right: 15px; }

...
For those interested, I whipped up a little LESS version today.

It’s a little different, but loops work a little differently in LESS. You just set up an iterator, kick off the mixin itself from within the mixin, and loop through as many times as you want.

helpers.less
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.generate-margin(@n, @i: 1, @direction: bottom, @type: m, @iterator: 5) when (@i =< @n) {

  @suffix: @i*@iterator;
  .@{type}-@{direction}-@{suffix} when (@type = m) {
    margin-@{direction}: @suffix + 0px;
  }
  .@{type}-@{direction}-@{suffix} when (@type = p) {
    padding-@{direction}: @suffix + 0px;
  }
  .generate-margin(@n, (@i + 1), @direction, @type, @iterator);
}

.generate-margin(15, 1, top, m, 5);
.generate-margin(15, 1, bottom, m, 5);
.generate-margin(15, 1, bottom, p, 5);
.generate-margin(15, 1, top, p, 5);

Generates:

application.css
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
.m-top-40 {
  margin-top: 40px;
}
.m-top-45 {
  margin-top: 45px;
}
.m-top-50 {
  margin-top: 50px;
}
.p-bottom-5 {
  margin-bottom: 5px;
}
.p-bottom-10 {
  margin-bottom: 10px;
}
.p-bottom-15 {
  margin-bottom: 15px;
}
.p-bottom-20 {
  margin-bottom: 20px;
}
.p-bottom-25 {
  margin-bottom: 25px;
...

Bonus: Stylus

I ran into a challenge with Stylus and found it was even easier to do there:

_helpers.styl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
sizes = 5 10 15 20 25 30 35 40 45 50
for num in sizes
  .mb-{num}
    margin-bottom: unit(num, px)
  .mt-{num}
    margin-top: unit(num, px)
  .ml-{num}
    margin-left: unit(num, px)
  .mr-{num}
    margin-right: unit(num, px)
  .pb-{num}
    padding-bottom: unit(num, px)
  .pt-{num}
    padding-top: unit(num, px)
  .pl-{num}
    padding-left: unit(num, px)
  .pr-{num}
    padding-right: unit(num, px)

Boom, you can generate them all with only a few lines of code.

This entire approach follows the pattern and way I like to work is to build principles and a foundation so each project is a bit easier.

It’s kind of like climbing a mountain a little faster each time.