DEV Community

Ria Pacheco
Ria Pacheco

Posted on • Edited on

Using Sass' @each and @for for Bootstrap-Like Behavior of Margin & Padding Classes

Bootstrap Backgrounder

Bootstrap includes margin and padding functionality that allows you to decide on what side of the element the margin or padding should be applied and how much of it should be layered on (multiple of the base font-size).

This means that if on an element you'd like to add padding to the top by 3 multiples of the base font-size, it'll add 45px of padding to the top of the element [base font size 15 x 3 = 45px] and is done with the class pt-3.

Problem

I don't like using Bootstrap libs since they restrict design, but I want the same class functionality that's used for margin and padding adjustments from directly within the HTML element.


Sass' @each and @for Features

If you're a .scss fan (css extension), then you can add the @each and @for methods to a global stylesheet for this same behavior:

// Margin
@each $abbr, $name in ("t": "top", "r": "right", "b": "bottom", "l": "left") {
  @for $i from 1 through 20 {
    .m#{$abbr}-#{$i} {
      margin-#{$name}: 1rem * $i;
    }
  }
}

// Padding
@each $abbr, $name in ("t": "top", "r": "right", "b": "bottom", "l": "left") {
  @for $i from 1 through 20 {
    .p#{$abbr}-#{$i} {
      padding-#{$name}: 1rem * $i;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

What's going on here?

  • Defined abbreviations associated to full words in an array
  • Defined limits of multiple (1 to 20)
  • Applied with template literals where abbreviation pairs should be applied along with the multiple

Top comments (4)

Collapse
 
ncqx profile image
ncqx • Edited

You could add both margin and padding inside the same for-loop :

@each $abbr, $name in ("t": "top", "r": "right", "b": "bottom", "l": "left") {
  @for $i from 1 through 20 {
    .p#{$abbr}-#{$i} {
      padding-#{$name}: 1rem * $i;
    }
    .m#{$abbr}-#{$i} {
     margin-#{$name}: 1rem * $i;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

You could get rid of having two for-loops (with two foreach instead), as the same logic is applied for both :

@each $spaceAbbr, $spaceProp in ('m': 'margin', 'p': 'padding') {
  @each $directionAbbr, $directionProp in ('t': 'top', 'r': 'right', 'b': 'bottom', 'l': 'left') {
    @for $i from 1 through 20 {
      .#{$spaceAbbr}#{$directionAbbr}-#{$i} {
       #{$spaceProp}-#{$directionProp}: 1rem * $i;
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Also, if like me the pattern is added as a suffix in your classes, like : element-mt-1, you could use a selector to target the end of your classes (and it will still work without prefixes) :

$spacer: 1rem;

@each $spaceAbbr, $spaceProp in ('m': 'margin', 'p': 'padding') {
  @each $directionAbbr, $directionProp in ('t': 'top', 'r': 'right', 'b': 'bottom', 'l': 'left') {
    @for $i from 1 through 20 {
      [class$='#{$spaceAbbr}#{$directionAbbr}-#{$i}'] {
        #{$spaceProp}-#{$directionProp}: $spacer * $i;
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Good practice : The unit for space should be out of the function and set in a variable where your variables are. Chances are you will use it a lot elsewhere and you want to edit it at one place only for quicker changes.

SCSS is endless fun <3

 
riapacheco profile image
Ria Pacheco

Let me know if you need some help! I love documentation…. Lololol

Collapse
 
riapacheco profile image
Ria Pacheco

Right?! Wot animations are ya using? Have you tried %placeholder selectors? I just discovered those aka it’s a way to essentially have a @mixin but from within the same stylesheet and I’m continuously blown away lol.

 
riapacheco profile image
Ria Pacheco

A) This should be a post!
B) I think I need to dive into this a bit more and try out the way you've laid it out here. You're next level.