Spacing

The _spacing.scss file contains the rules to set the spacing system of your web project.

Guide content:

  1. 📝How to set Spacing using the CodyHouse Framework
  2. 🚀How to use the Spacing Editor

How to set Spacing using the CodyHouse Framework #

Spacing scale #

Step one of setting a spacing system is creating a scale of (spacing) values. To create a scale of non-linear values you need 1) a unit or base value and 2) a multiplier.

In our framework, the --space-unit is equal to 1em, while the modular scale is based on the Fibonacci sequence (with a small tweak):

:root {
    --space-unit:  1em;
    --space-xxxxs: calc(0.125 * var(--space-unit));
    --space-xxxs:  calc(0.25 * var(--space-unit));
    --space-xxs:   calc(0.375 * var(--space-unit));
    --space-xs:    calc(0.5 * var(--space-unit));
    --space-sm:    calc(0.75 * var(--space-unit));
    --space-md:    calc(1.25 * var(--space-unit));
    --space-lg:    calc(2 * var(--space-unit));
    --space-xl:    calc(3.25 * var(--space-unit));
    --space-xxl:   calc(5.25 * var(--space-unit));
    --space-xxxl:  calc(8.5 * var(--space-unit));
    --space-xxxxl: calc(13.75 * var(--space-unit));
}

Note: the first time we read about applying the Fibonacci sequence to a scale of spacing values was in this excellent article by The Scenery.

It's important to be aware of the consequences of using Em units in the spacing system. The Em unit is a relative unit equal to the current font size. In most browsers, the default font-size (before CSS styling is applied) is 16 pixels. Therefore we can assume 1em = 16px. However, if you edit the font-size of an element, 1em is no longer 16px (for that element), but it’s equal to the new font-size. What appears like a lack of control, is a powerful responsiveness shortcut.

In our article on Typography, we explain how all font sizes are intertwined and obtained by multiplying a --text-base-size variable (equal to 1em) by a ratio, to generate the type scale. That means that the --text-base-size variable is the controller of the whole type system. If you increase its value at a specific media query, all the text size variables change accordingly.

@supports(--css: variables) {
  :root {
    @include breakpoint(md) {
      --text-base-size: 1.25em;
    }
  }
}

⚠️ Important: we wrap the variable update at the md (medium) breakpoint into a @supports(--css: variables) rule to prevent the postcss-css-variables plugin from generating a fallback (Which, in this case, would result in a lot of extra code). More info on our Globals page.

By updating just one variable, you get this:

edit text base size

Not just that! Since the spacing unit is equal to 1em, and all other spacing values are multipliers of the unit value, when we update the --text-base-size variable, we affect the spacing as well 💪.

Look how this method affects typography and spacing at the same time:

edit typography and spacing

This is the effect of updating a single variable (--text-base-size). No additional media queries needed so far. All left to do is using the spacing variables to set paddings and margins on a component level:

.header__top {
    background: var(--color-contrast-higher);
    padding: var(--space-sm);
    text-align: center;

    a {
        color: var(--white);
        @include fontSmooth;
    }
}

.header__main {
    border-bottom: 1px solid var(--color-border);
    padding-top: var(--space-sm);
    padding-bottom: var(--space-sm);
    background: var(--color-bg);
}

.header__nav {
    ul {
        display: flex;
    }

    li {
        margin-right: var(--space-md);

        &:last-child {
            margin-right: 0;
        }
    }
}

What if you want to update all spacing values at once, without having to change the --text-base-size variable? Just update the --space-unit variable:

:root {
    --space-unit:  1em;
    --space-xxxxs: calc(0.125 * var(--space-unit)); 
    --space-xxxs:  calc(0.25 * var(--space-unit));
    --space-xxs:   calc(0.375 * var(--space-unit));
    --space-xs:    calc(0.5 * var(--space-unit));
    --space-sm:    calc(0.75 * var(--space-unit));
    --space-md:    calc(1.25 * var(--space-unit));
    --space-lg:    calc(2 * var(--space-unit));
    --space-xl:    calc(3.25 * var(--space-unit));
    --space-xxl:   calc(5.25 * var(--space-unit));
    --space-xxxl:  calc(8.5 * var(--space-unit));
    --space-xxxxl: calc(13.75 * var(--space-unit));
}

@supports(--css: variables) {
  :root {
    @include breakpoint(md) {
      --space-unit:  1.25em;
    }
  }
}
It is true that by embracing a method like this one you lose some of your “visual” control, but it’s in favor of simplicity and maintainability.

Because the updated --space-unit value is wrapped in a @support feature query, these changes will be visible only in browsers that support CSS Variables (more info on why this is a good idea in our Globals docs page).

Unfortunately, you can't target a single component and edit the --space-unit value expecting a cascade effect. This won't work unless the whole spacing scale is declared in that component as well (or at least the space values you wish to affect).

This won't work:

.component {
    --space-unit: 2em;
}

Set a default padding for all components #

There will be cases where you need different components to have the same padding. This is why it comes in handy to store the "default" component padding in a variable:

:root {
    --space-unit:  1em;
    --space-xxxxs: calc(0.125 * var(--space-unit)); 
    --space-xxxs:  calc(0.25 * var(--space-unit));
    --space-xxs:   calc(0.375 * var(--space-unit));
    --space-xs:    calc(0.5 * var(--space-unit));
    --space-sm:    calc(0.75 * var(--space-unit));
    --space-md:    calc(1.25 * var(--space-unit));
    --space-lg:    calc(2 * var(--space-unit));
    --space-xl:    calc(3.25 * var(--space-unit));
    --space-xxl:   calc(5.25 * var(--space-unit));
    --space-xxxl:  calc(8.5 * var(--space-unit));
    --space-xxxxl: calc(13.75 * var(--space-unit));
    
    --component-padding: var(--space-md);
}

In the documentation page on Grid & Layout we explain how the --component-padding variable can be used together with the .container class to align the content at the edges of the screen. Here's a code example:

Margin utility classes #

While it’s safe to include padding directly in your component CSS, including margins can cause layout issues. To be clear, we’re referring to the main components, those blocks that define your main layout (not a <button> component, but a <section class=”myComponent”> element).

If we imagine these components as blocks distributed in layouts, then information about margins and position should be stored in the abstract layout element, not the component. For example, you may end up using the same component in two different layouts, in one case you need to apply a margin-bottom, in another you don’t. You can see why including the margin-bottom in the component CSS may not be a good idea in this case.

For these reasons, we included utility classes for the top/bottom margins:

.margin-top, .margin-top--md {
    margin-top: var(--space-md);
}

.margin-top--sm {
    margin-top: var(--space-sm);
}

.margin-top--lg {
    margin-top: var(--space-lg);
}

.margin-top--xl {
    margin-top: var(--space-xl);
}

.margin-top--xxl {
    margin-top: var(--space-xxl);
}

.margin-bottom, .margin-bottom--md {
    margin-bottom: var(--space-md);
}

.margin-bottom--sm {
    margin-bottom: var(--space-sm);
}

.margin-bottom--lg {
    margin-bottom: var(--space-lg);
}

.margin-bottom--xl {
    margin-bottom: var(--space-xl);
}

.margin-bottom--xxl {
    margin-bottom: var(--space-xxl);
}

Custom spacing values #

What if you’re setting a margin on an element, and --space-sm looks too small, while --space-md is too big? Working with a set of predefined variables means that sometimes you have to compromise (for the sake of the system maintainability).

BUT! If you do need to use a spacing value that is not included in your spacing scale, and you don’t want to edit or break the system, you can take advantage of the CSS calc function:

.nav__item {
  margin-right: calc(var(--space-sm) * 1.1);
}

Edit spacing values at component level #

If you want to modify the --space-unit value for a specific component, you can use the spaceUnit mixin:

.component-name {
  @include spaceUnit(1.2em);
}

You can use this mixin to switch from a spacing system based on em to one based on rem:

.component-name {
  @include spaceUnit(1rem);
}

This could be useful if you don't want your spacing variables to change when the font-size of the body (or component elements) is updated.

How to use the Spacing Editor #

The Spacing Editor is a web design tool that allows you to create a spacing system in SCSS. It's based on the CodyHouse Framework. You can use it to generate a spacing scale and set responsive rules.

✅ When you save your changes, the spacing of the components is updated with the rules you set in the Editor.