Spacing

Description

A series of utilities for responsive spacing and gutter spacing, covering margin, padding, top/left/right/bottom, inset/inset-x/inset-y and gap/row-gap/column-gap.

v1.1.0 adds logical properties:

  • margin-inline-start/ms- (MDN)
  • margin-inline-end/me- (MDN)
  • padding-inline-start/ps- (MDN)
  • padding-inline-end/pe- (MDN)
  • inset-inline-start/start (MDN)
  • inset-inline-end/end (MDN)

Setup

In addition to the required $structure map (Setup), you should add a $spacing map to your _tokens.scss, with the following format:

_tokens.scss
$spacing: (
  outer-1: (
    xs: 64px,
    lg: 96px
  ),
  inner-1: (
    xs: 24px,
    md: 40px,
    lg: 64px
  ),
  inner-2: (
    xs: 16px,
    md: 24px,
    lg: 32px
  )
);

Output

Responsive spacing group classes

Responsive spacing classes, for each of the responsive spacing groups.
For example, looking at $outer-1:

_tokens.scss
$spacing: (
  outer-1: (
    xs: 64px,
    lg: 96px
  ),
);

First we would get :root variables:

app.css
:root {
  --SPACING_VARs: "at this breakpoint ↓";
  --spacing-outer-1: 4rem;
}

@media screen and (min-width: 544px) {
  :root {
    --SPACING_VARs: "at this breakpoint ↓";
    --spacing-outer-1: 4rem;
  }
}
@media screen and (min-width: 650px) {
  :root {
    --SPACING_VARs: "at this breakpoint ↓";
    --spacing-outer-1: 4rem;
  }
}
@media screen and (min-width: 990px) {
  :root {
    --SPACING_VARs: "at this breakpoint ↓";
    --spacing-outer-1: 6rem;
  }
}
@media screen and (min-width: 1300px) {
  :root {
    --SPACING_VARs: "at this breakpoint ↓";
    --spacing-outer-1: 6rem;
  }
}
@media screen and (min-width: 1520px) {
  :root {
    --SPACING_VARs: "at this breakpoint ↓";
    --spacing-outer-1: 6rem;
  }
}

Then the corresponding placeholder and CSS classes:

SCSS Placeholder CSS Class Properties
%mt-outer-1 .mt-outer-1 margin-top: var(--spacing-outer-1);
%mb-outer-1 .mb-outer-1 margin-bottom: var(--spacing-outer-1);
%ml-outer-1 .ml-outer-1 margin-left: var(--spacing-outer-1);
%mr-outer-1 .mr-outer-1 margin-right: var(--spacing-outer-1);
%m-outer-1 .m-outer-1 margin: var(--spacing-outer-1);
%mx-outer-1 .mx-outer-1 margin-right: var(--spacing-outer-1);
margin-left: var(--spacing-outer-1);
%my-outer-1 .my-outer-1 margin-top: var(--spacing-outer-1);
margin-bottom: var(--spacing-outer-1);
%ms-outer-1 .ms-outer-1 margin-inline-start: var(--spacing-outer-1);
%me-outer-1 .me-outer-1 margin-inline-end: var(--spacing-outer-1);
%pt-outer-1 .pt-outer-1 padding-top: var(--spacing-outer-1);
%pb-outer-1 .pb-outer-1 padding-bottom: var(--spacing-outer-1);
%pl-outer-1 .pl-outer-1 padding-left: var(--spacing-outer-1);
%pr-outer-1 .pr-outer-1 padding-right: var(--spacing-outer-1);
%p-outer-1 .p-outer-1 padding: var(--spacing-outer-1);
%px-outer-1 .px-outer-1 padding-right: var(--spacing-outer-1);
padding-left: var(--spacing-outer-1);
%py-outer-1 .py-outer-1 padding-top: var(--spacing-outer-1);
padding-bottom: var(--spacing-outer-1);
%ps-outer-1 .ps-outer-1 padding-inline-start: var(--spacing-outer-1);
%pe-outer-1 .pe-outer-1 padding-inline-end: var(--spacing-outer-1);
%top-outer-1 .top-outer-1 top: var(--spacing-outer-1);
%bottom-outer-1 .bottom-outer-1 bottom: var(--spacing-outer-1);
%left-outer-1 .left-outer-1 left: var(--spacing-outer-1);
%right-outer-1 .right-outer-1 right: var(--spacing-outer-1);
%inset-outer-1 .inset-outer-1 inset: var(--spacing-outer-1);
%inset-x-outer-1 .inset-x-outer-1 inset-x: var(--spacing-outer-1);
%inset-y-outer-1 .inset-y-outer-1 inset-y: var(--spacing-outer-1);
%start-outer-1 .start-outer-1 inset-inline-start: var(--spacing-outer-1);
%end-outer-1 .end-outer-1 inset-inline-end: var(--spacing-outer-1);
%gap-outer-1 .gap-outer-1 gap: var(--spacing-outer-1);
%gap-x-outer-1 .gap-x-outer-1 column-gap: var(--spacing-outer-1);
%gap-y-outer-1 .gap-y-outer-1 row-gap: var(--spacing-outer-1);

And negative classes where applicable:

SCSS Placeholder CSS Class Properties
%-mt-outer-1 .-mt-outer-1 margin-top: calc(var(--spacing-outer-1) * -1);
%-mb-outer-1 .-mb-outer-1 margin-bottom: calc(var(--spacing-outer-1) * -1);
%-ml-outer-1 .-ml-outer-1 margin-left: calc(var(--spacing-outer-1) * -1);
%-mr-outer-1 .-mr-outer-1 margin-right: calc(var(--spacing-outer-1) * -1);
%-m-outer-1 .-m-outer-1 margin: calc(var(--spacing-outer-1) * -1);
%-mx-outer-1 .-mx-outer-1 margin-right: calc(var(--spacing-outer-1) * -1);
margin-left: calc(var(--spacing-outer-1) * -1);
%-my-outer-1 .-my-outer-1 margin-top: calc(var(--spacing-outer-1) * -1);
margin-bottom: calc(var(--spacing-outer-1) * -1);
%-ms-outer-1 .-ms-outer-1 margin-inline-start: calc(var(--spacing-outer-1) * -1);
%-me-outer-1 .-me-outer-1 margin-inline-end: calc(var(--spacing-outer-1) * -1);
%-top-outer-1 .-top-outer-1 top: calc(var(--spacing-outer-1) * -1);
%-bottom-outer-1 .-bottom-outer-1 bottom: calc(var(--spacing-outer-1) * -1);
%-left-outer-1 .-left-outer-1 left: calc(var(--spacing-outer-1) * -1);
%-right-outer-1 .-right-outer-1 right: calc(var(--spacing-outer-1) * -1);
%-inset-outer-1 .-inset-outer-1 inset: calc(var(--spacing-outer-1) * -1);
%-inset-x-outer-1 .-inset-x-outer-1 inset-x: calc(var(--spacing-outer-1) * -1);
%-inset-y-outer-1 .-inset-y-outer-1 inset-y: calc(var(--spacing-outer-1) * -1);

As each of these points to a CSS variable and so you can override per element if required.

Gutter spacing classes

Also generated are utility placeholders and CSS classes for inner gutter and outer gutters:

SCSS Placeholder CSS Class Properties
%mt-gutter .mt-gutter margin-top: var(--inner-gutter);
%mb-gutter .mb-gutter margin-bottom: var(--inner-gutter);
%ml-gutter .ml-gutter margin-left: var(--inner-gutter);
%mr-gutter .mr-gutter margin-right: var(--inner-gutter);
%m-gutter .m-gutter margin: var(--inner-gutter);
%mx-gutter .mx-gutter margin-right: var(--inner-gutter);
margin-left: var(--inner-gutter);
%my-gutter .my-gutter margin-top: var(--inner-gutter);
margin-bottom: var(--inner-gutter);
%ms-gutter .ms-gutter margin-inline-start: var(--inner-gutter);
%me-gutter .me-gutter margin-inline-end: var(--inner-gutter);
%pt-gutter .pt-gutter padding-top: var(--inner-gutter);
%pb-gutter .pb-gutter padding-bottom: var(--inner-gutter);
%pl-gutter .pl-gutter padding-left: var(--inner-gutter);
%pr-gutter .pr-gutter padding-right: var(--inner-gutter);
%p-gutter .p-gutter padding: var(--inner-gutter);
%px-gutter .px-gutter padding-right: var(--inner-gutter);
padding-left: var(--inner-gutter);
%py-gutter .py-gutter padding-top: var(--inner-gutter);
padding-bottom: var(--inner-gutter);
%ps-gutter .ps-gutter padding-inline-start: var(--inner-gutter);
%pe-gutter .pe-gutter padding-inline-end: var(--inner-gutter);
%top-gutter .top-gutter top: var(--inner-gutter);
%bottom-gutter .bottom-gutter bottom: var(--inner-gutter);
%left-gutter .left-gutter left: var(--inner-gutter);
%right-gutter .right-gutter right: var(--inner-gutter);
%inset-gutter .inset-gutter inset: var(--inner-gutter);
%inset-x-gutter .inset-x-gutter inset-x: var(--inner-gutter);
%inset-y-gutter .inset-y-gutter inset-y: var(--inner-gutter);
%start-gutter .start-gutter inset-inline-start: var(--inner-gutter);
%end-gutter .end-gutter inset-inline-end: var(--inner-gutter);
%gap-gutter .gap-gutter gap: var(--inner-gutter);
%gap-x-gutter .gap-x-gutter column-gap: var(--inner-gutter);
%gap-y-gutter .gap-y-gutter row-gap: var(--inner-gutter);
%-mt-gutter .-mt-gutter margin-top: calc(var(--inner-gutter) * -1);
%-mb-gutter .-mb-gutter margin-bottom: calc(var(--inner-gutter) * -1);
%-ml-gutter .-ml-gutter margin-left: calc(var(--inner-gutter) * -1);
%-mr-gutter .-mr-gutter margin-right: calc(var(--inner-gutter) * -1);
%-m-gutter .-m-gutter margin: calc(var(--inner-gutter) * -1);
%-mx-gutter .-mx-gutter margin-right: calc(var(--inner-gutter) * -1);
margin-left: calc(var(--inner-gutter) * -1);
%-my-gutter .-my-gutter margin-top: calc(var(--inner-gutter) * -1);
margin-bottom: calc(var(--inner-gutter) * -1);
%-ms-gutter .-ms-gutter margin-inline-start: calc(var(--inner-gutter) * -1);
%-me-gutter .-me-gutter margin-inline-end: calc(var(--inner-gutter) * -1);
%-top-gutter .-top-gutter top: calc(var(--inner-gutter) * -1);
%-bottom-gutter .-bottom-gutter bottom: calc(var(--inner-gutter) * -1);
%-left-gutter .-left-gutter left: calc(var(--inner-gutter) * -1);
%-right-gutter .-right-gutter right: calc(var(--inner-gutter) * -1);
%-inset-gutter .-inset-gutter inset: calc(var(--inner-gutter) * -1);
%-inset-x-gutter .-inset-x-gutter inset-x: calc(var(--inner-gutter) * -1);
%-inset-y-gutter .-inset-y-gutter inset-y: calc(var(--inner-gutter) * -1);
%mt-outer-gutter .mt-outer-gutter margin-top: var(--outer-gutter);
%mb-outer-gutter .mb-outer-gutter margin-bottom: var(--outer-gutter);
%ml-outer-gutter .ml-outer-gutter margin-left: var(--outer-gutter);
%mr-outer-gutter .mr-outer-gutter margin-right: var(--outer-gutter);
%m-outer-gutter .m-outer-gutter margin: var(--outer-gutter);
%mx-outer-gutter .mx-outer-gutter margin-right: var(--outer-gutter);
margin-left: var(--outer-gutter);
%my-outer-gutter .my-outer-gutter margin-top: var(--outer-gutter);
margin-bottom: var(--outer-gutter);
%ms-outer-gutter .ms-outer-gutter margin-inline-start: var(--outer-gutter);
%me-outer-gutter .me-outer-gutter margin-inline-end: var(--outer-gutter);
%pt-outer-gutter .pt-outer-gutter padding-top: var(--outer-gutter);
%pb-outer-gutter .pb-outer-gutter padding-bottom: var(--outer-gutter);
%pl-outer-gutter .pl-outer-gutter padding-left: var(--outer-gutter);
%pr-outer-gutter .pr-outer-gutter padding-right: var(--outer-gutter);
%p-outer-gutter .p-outer-gutter padding: var(--outer-gutter);
%px-outer-gutter .px-outer-gutter padding-right: var(--outer-gutter);
padding-left: var(--outer-gutter);
%py-outer-gutter .py-outer-gutter padding-top: var(--outer-gutter);
padding-bottom: var(--outer-gutter);
%ps-outer-gutter .ps-outer-gutter padding-inline-start: var(--outer-gutter);
%pe-outer-gutter .pe-outer-gutter padding-inline-end: var(--outer-gutter);
%top-outer-gutter .top-outer-gutter top: var(--outer-gutter);
%bottom-outer-gutter .bottom-outer-gutter bottom: var(--outer-gutter);
%left-outer-gutter .left-outer-gutter left: var(--outer-gutter);
%right-outer-gutter .right-outer-gutter right: var(--outer-gutter);
%inset-outer-gutter .inset-outer-gutter inset: var(--outer-gutter);
%inset-x-outer-gutter .inset-x-outer-gutter inset-x: var(--outer-gutter);
%inset-y-outer-gutter .inset-y-outer-gutter inset-y: var(--outer-gutter);
%start-outer-gutter .start-outer-gutter inset-inline-start: var(--outer-gutter);
%end-outer-gutter .end-outer-gutter inset-inline-end: var(--outer-gutter);
%gap-outer-gutter .gap-outer-gutter gap: var(--outer-gutter);
%gap-x-outer-gutter .gap-x-outer-gutter column-gap: var(--outer-gutter);
%gap-y-outer-gutter .gap-y-outer-gutter row-gap: var(--outer-gutter);
%-mt-outer-gutter .-mt-outer-gutter margin-top: calc(var(--outer-gutter) * -1);
%-mb-outer-gutter .-mb-outer-gutter margin-bottom: calc(var(--outer-gutter) * -1);
%-ml-outer-gutter .-ml-outer-gutter margin-left: calc(var(--outer-gutter) * -1);
%-mr-outer-gutter .-mr-outer-gutter margin-right: calc(var(--outer-gutter) * -1);
%-m-outer-gutter .-m-outer-gutter margin: calc(var(--outer-gutter) * -1);
%-mx-outer-gutter .-mx-outer-gutter margin-right: calc(var(--outer-gutter) * -1);
margin-left: calc(var(--outer-gutter) * -1);
%-my-outer-gutter .-my-outer-gutter margin-top: calc(var(--outer-gutter) * -1);
margin-bottom: calc(var(--outer-gutter) * -1);
%-ms-outer-gutter .-ms-outer-gutter margin-inline-start: calc(var(--outer-gutter) * -1);
%-me-outer-gutter .-me-outer-gutter margin-inline-end: calc(var(--outer-gutter) * -1);
%-top-outer-gutter .-top-outer-gutter top: calc(var(--outer-gutter) * -1);
%-bottom-outer-gutter .-bottom-outer-gutter bottom: calc(var(--outer-gutter) * -1);
%-left-outer-gutter .-left-outer-gutter left: calc(var(--outer-gutter) * -1);
%-right-outer-gutter .-right-outer-gutter right: calc(var(--outer-gutter) * -1);
%-inset-outer-gutter .-inset-outer-gutter inset: calc(var(--outer-gutter) * -1);
%-inset-x-outer-gutter .-inset-x-outer-gutter inset-x: calc(var(--outer-gutter) * -1);
%-inset-y-outer-gutter .-inset-y-outer-gutter inset-y: calc(var(--outer-gutter) * -1);

Demo

The following "box" has responsive spacing margin and internal padding classes, if you resize your browser you'll see the spacing alters.

box

document.html
<div class="mt-outer-1 p-inner-1 bg-accent">
  <div class="p-inner-2 bg-primary">
    <p>box</p>
  </div>
</div>

Gutter classes can be used to insert gutter sized spacing:

box

box

document.html
<div class="py-inner-2 bg-accent" style="display: flex; flex-flow: row nowrap;">
  <div class="colspan-1 mr-gutter bg-primary" style="padding: 5px;">
    <p>box</p>
  </div>
  <div class="bg-primary" style="padding: 5px;">
    <p>box</p>
  </div>
</div>

Notes

As you can see, this generates a lot of CSS classes - you will want to purge your CSS of unused classes to remove any of these that you don't use.

Alternatively, if you don't want to generate the CSS classes, see CSS-Class-Generation.

You maybe wondering why we don't also generate spacing classes linked to rem values such as those within Tailwind. When writing SCSS to style your components, you would place any none non systemised spacing inside your SCSS files. Though you may choose to use the systemised responsive spacing classes in your HTML, they can help debugging as its clear which spacing group is being applied.