Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic Spacing classes with SASS

Tags:

html

css

sass

Hi All!

I'm working with a sass file that has a looooooong set of hard-coded helper classes for padding and margins. Because we're working with scss here, this is redundant and can be solved with a sass function or something.
The trouble I'm having is actually writing the fancy sass to do the heavy lifting on this, because this requires... math. gasp


It currently looks like this...

// Spacing
$spacer: 1rem;

// Margin Helpers
.m-0 {margin: 0;}
.m-1 {margin: ($spacer * .25);}
.m-2 {margin: ($spacer * .5);}
.m-3 {margin: ($spacer);}
.m-4 {margin: ($spacer * 1.5);}
.m-5 {margin: ($spacer * 3);}

.mt-0 {margin-top: 0;}
.mt-1 {margin-top: ($spacer * .25);}
.mt-2 {margin-top: ($spacer * .5);}
.mt-3 {margin-top: ($spacer);}
.mt-4 {margin-top: ($spacer * 1.5);}
.mt-5 {margin-top: ($spacer * 3);}

.ml-0 {margin-left: 0;}
.ml-1 {margin-left: ($spacer * .25);}
.ml-2 {margin-left: ($spacer * .5);}
.ml-3 {margin-left: ($spacer);}
.ml-4 {margin-left: ($spacer * 1.5);}
.ml-5 {margin-left: ($spacer * 3);}

Now imagine this ^^ with every side and spacing, all hard-coded, and repeated for padding helpers. Yeah, my jaw is on the ground too.

I'd like to turn the above mess, into a sass function, mixin, whatever would be ideal for this conundrum. I've scoured the depths of the internet and have found a lot that are either more complicated than necessary, or can't do the math I need. I'm not that experienced with scss functions and mixins so don't bully me just yet.


I was experimenting for like 3 hours until I finally gave up; during which I had found and was reading a few articles that may be able to help but I couldn't wrap my noodle of a brain around it quite, so I'll include those below.

SASS Margin and Padding Helpers Loop. Generates .m-t-10 type helper classes.

How to dynamically build helper classes using SCSS


I'll give you a giant bear of a virtual hug if you can help me fix this disgrace of a sass file :)


Thanks in advance!
~ Josh

like image 393
joshwcorbett Avatar asked Dec 05 '22 09:12

joshwcorbett


1 Answers

Here's a pretty simple mixin to do what you want:

@mixin generate($prefix, $property) {
  // List of sizes to generate for each
  $sizes: [0, .25, .5, 1, 1.5, 3];
  // Spacing to multiply the sizes by
  $spacing: 1rem;
  
  // Loop through all of the sizes(we use @for rather than @each, as we want access to the index)
  @for $i from 1 through length($sizes) {
    // Get the size for the current index
    $size: nth($sizes, $i);
    
    // Create the rule
    .#{$prefix}-#{$i - 1} {
      #{$property}: $spacing * $size;
    }
  }
}

The usage of this mixin would look like so:

@include generate(ml, margin-left);

And would compile to:

.ml-0 {
  margin-left: 0rem;
}

.ml-1 {
  margin-left: 0.25rem;
}

.ml-2 {
  margin-left: 0.5rem;
}

.ml-3 {
  margin-left: 1rem;
}

.ml-4 {
  margin-left: 1.5rem;
}

.ml-5 {
  margin-left: 3rem;
}

You can play around with this sassmeister.

When it comes to generating these for a large number of properties, you could take it another step, and use an @each:

$rules: [
  [ml, margin-left],
  [mt, margin-top],
  [mb, margin-bottom],
  [mr, margin-right],
];

@each $item in $rules {
  @include generate(nth($item, 1), nth($item, 2));
}

And another sassmeister for your convenience.

While you could go deeper and just loop over the -top, -bottom, etc so you just have to specify a property and everything else is generated, I don't know your use case, and you can figure it out.

like image 59
Jacob Gray Avatar answered Dec 14 '22 03:12

Jacob Gray