DEV Community

Alex Gurr
Alex Gurr

Posted on

Creating a style utility file with some SCSS magic ✨

You might have used style frameworks in the past like Bootstrap or Bulma. Most of these types of libraries provide utility classes you can easily use in your HTML layouts, such as ml-10 for left margin, or pr-5 for right padding. One way of doing this is with a super long file and repetitive class declarations. Not very readable or scalable though is it?

In this article, we'll dive into making our own utility style file with scss, using some cool scss magic you might not have used before. In our example we'll be working with margin, but you could easily reproduce with any properties you like! The way we do this is flexible -- you provide the values for your classes (instead of mapping 1-100 for example).

 

Let's make a new .scss file

Pretty easy. I'll let you decide on how you want to do this.

Tip: you can structure your scss files similarly to JS files and make it super readable! I love using index.scss files to group imports within a folder, then having the parent import the index file.

 

Let's set up some variables

We're going to need 4 variables (a couple are optional):

auto (optional) - good practice to extract constants to variables. This is used to hold the auto value.

directions - an array of strings, to cover the 4 different directions our margin could be (top, bottom, left, right)

css-property-map (optional) - A scss map to map our directions above to CSS properties. SCSS maps work similarly to JS, with a key/value. I use this because I want my utility classes to be shorthand/small in size. You could avoid this by having the full direction in your class.

sizes: an array of CSS values. These are the utility classes/values we want to generate. I've also included an auto value which gets handled separately as it's not a standard px value.

$auto: auto;
$directions: 't', 'b', 'l', 'r';
$css-property-map: ('t': margin-top, 'b': margin-bottom, 'l': margin-left, 'r': margin-right);
$sizes: 0, 5, 10, 20, 30, 40, 50, 60, 100, $auto;
Enter fullscreen mode Exit fullscreen mode

 

And now some loops

We set up a couple of dynamic loops (think for each loop in JS). This will give us all sizes for each direction.

@each $direction in $directions {
  @each $size in $sizes {
    // Classes coming here
  }
}
Enter fullscreen mode Exit fullscreen mode

 

Generate the actual utility class

We dynamically create CSS classes for each direction/size combo. This will give us the classes in a .ml-5 format.

@each $direction in $directions {
  @each $size in $sizes {
    .m#{$direction}-#{$size} {
      // CSS property/values coming here
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

 

Setup the CSS properties and values

We compare the size to our previously defined auto value. If it's auto, we don't need to build a px value.

#{map-get($css-property-map, $direction)} let's us build dynamic CSS properties. Let's deep dive into what each bit means:

  • #{} - inject an SCSS variable into CSS

  • map-get(map, key) - pull out a value from a specific map with the passed key

@if $size == $auto {
  #{map-get($css-property-map, $direction)}: $auto;
} @else {
  #{map-get($css-property-map, $direction)}: #{$size}px;
}
Enter fullscreen mode Exit fullscreen mode

 

Complete util code

$auto: auto;
$directions: 't', 'b', 'l', 'r';
$css-property-map: ('t': margin-top, 'b': margin-bottom, 'l': margin-left, 'r': margin-right);
$sizes: 0, 5, 10, 20, 30, 40, 50, 60, 100, $auto;

@each $direction in $directions {
  @each $size in $sizes {
    .m#{$direction}-#{$size} {
      @if $size == $auto {
        #{map-get($css-property-map, $direction)}: $auto;
      } @else {
        #{map-get($css-property-map, $direction)}: #{$size}px;
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

 

And that's it! We've now dynamically generated a collection of top/bottom/left/right margin classes.

Discussion (0)