The Sass and CSS 3 logos offset in a pattern across a design grid.
Calendar   3 April, 2017 //

Using Sass and CSS3 Flex as a grid system

#Frontend
#HTML, CSS & Javascript
#Tutorial
Darren Fisher, Creative Director at Pivale Drupal agency - a bearded man with dark hair and glasses.

Written by

Darren Fisher

Creative Director

Share Arrow down

Warning
Technical disclaimer
This article is over a year old and contains technical instructions which may be out of date. The advice given may no longer be best practice.

We used to base all of our responsive design work on the singularity framework which utilised CSS floats to achieve a grid that could be manipulated at different breakpoints to suit multiple devices. There were many niggles with using this system - and none of them were to do with Singularity itself and more to do with CSS floats which for the most part always seemed to be the wrong approach - a little bit like using HTML tables for layout back in the good old days.

Now, there are whispers on the winds that a grid system is coming directly to CSS - but until such time as these initiatives become production-ready what were we to do?

With the arrive of flex in CSS3, layouts are now a joy to achieve but they still don't quite form a grid system. However, using Sass combined with the power of some of the latest CSS3 technology we can make our own grid system quite easily and I wanted to share my grid system with you in the spirit of open source.

Pre-warning: a decent level of understanding of Sass and CSS3 will be required to understand and utilise this information.

The method

You'll need to have a project up and running with Sass (SCSS) and will hopefully have a variables folder with some Sass partials in it. In your 'variables' directory add a new sass partial and call it something like "_gutters.scss". Open the file and add a variable so that we have a gutter (width of your choice) to work with. The sass will look something like this:

$gutter-width: 40px;

Now that we have a gutter width stored in a variable (so that we can easily change it later if required) we can move on to setting up the grid framework. This is done via a sass mixin. Personally I store my mixings in the 'abstractions' directory but you may have your own preference. The main thing is to make sure that your mixins are the first thing that are compiled before you start working on any production code. So in my 'abstractions' directory I'll create another sass partial and call it something like "_mixins.scss". Open the file and create a mixin:

@mixin grid-span($columns) {
  $gutters: ($columns - 1);

  flex-basis: calc((100% / #{$columns}) - ((#{$gutter-width} * #{$gutters}) / #{$columns}));
  flex-grow: 0;
  flex-shrink: 0;
  width: calc((100% / #{$columns}) - ((#{$gutter-width} * #{$gutters}) / #{$columns}));
}

Whoa?!?! What the heck is going on here? If this looks utterly alien to you - never fear. I'll explain what's going on here.

Firstly we've created a mixin (a block of code which we can use again and again by entering a variable. First of all let me give you an example of how we would call this code:

.foo {
  display: flex;

  .bar {
    @include grid-span(3);

    margin-right: $gutter-width;

    &:nth-child(3n) {
      margin-right: 0;
    }

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

What this is doing is telling the parent wrapper that we want to display flex which then makes all child items 'flex items'. This allows us to give them flex properties that make them behave in a grid like format but filling these properties out time and time again is frustrating and not time-efficient.

So, enter our mixin. As you can see we called the mixing using the code:

@include grid-span(3);

What this is doing is saying we want to include the code we've written in our mixin and to pass the value of three to the variable within the mixin. So let's show what that would look like in static code:

@mixin grid-span(3) {
  $gutters: (3 - 1);

  flex-basis: calc((100% / 3) - ((#{$gutter-width} * #{$gutters}) / 3));
  flex-grow: 0;
  flex-shrink: 0;
  width: calc((100% / 3) - ((#{$gutter-width} * #{$gutters}) / 3));
}

Hopefully this is now looking less scary. Now we've passed '3' as a value to the $columns variable we will also have a fixed value for the $gutters variable as this is formed of a calculation which subtracts 1 from the $columns value. We also defined our $gutter-width variable so we can swap that out for a value and start to make sense of what's happening inside this mixin:

@mixin grid-span(3) {
  $gutters: (3 - 1);

  flex-basis: calc((100% / 3) - ((40px * 2) / 3));
  flex-grow: 0;
  flex-shrink: 0;
  width: calc((100% / 3) - ((40px * 2) / 3));
}

So now the mixin has all the values it needs and in sass we'd now be looking at this if we'd written this statically:

.foo {
  display: flex;

  .bar {
    flex-basis: calc((100% / 3) - ((40px * 2) / 3));
    flex-grow: 0;
    flex-shrink: 0;
    margin-right: 40px;
    width: calc((100% / 3) - ((40px * 2) / 3));

    &:nth-child(3n) {
      margin-right: 0;
    }

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

So let's tackle the calculation so we know what's happening:

Visualisation of the calculation.

Calc 1

100% (eg. a 1200px container) ÷ 3 (number of columns) = 400px

Visualisation of the calculation.

Calc 2a

40px (gutter width) x 2 (number of gutters) = 80px

Visualisation of the calculation.

Calc 2b

80px (total sum of gutter widths) ÷ 3 (number of columns) = 26.66px

Visualisation of the calculation.

Calc 3

400px - 26.66px = 373.34px

Visualisation of the calculation.

Working backwards to check

So our child elements are given a width of 373.34px. If we do 373.34px multiplied by 3 we get 1120* and then if we add our total sum for the gutters which is 80px we end up back at 1200px!

*Rounded by browser to whole figure.

Visualisation of the calculation.

Guttery biscuit base

The gutters are added by the following code:

margin-right: 40px;

&:nth-child(3n) {
  margin-right: 0;
}

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

This tells every child element to have a margin-right of 40px unless they are a multiple of 3 (the last column in the row) or the very last child (in case we want to do some funky central alignment trickery!

Browser oddities

The keen-eyed will be asking the question:

Why on earth are we implementing a flex-basis and fixed width value that are exactly the same?

Come on! You know the answer. It's not just internet explorer either! Edge, Safari and Firefox all have rendering oddities when it comes to using flex and calc in combination. The safest way to have this render properly in every browser is to include both flex-basis and width at the same time.

I can also hear those in the know groaning about this bit of code:

flex-basis: calc((100% / #{$columns}) - ((#{$gutter-width} * #{$gutters}) / #{$columns}));
flex-grow: 0;
flex-shrink: 0;

The recommended syntax is the short-hand version which would look like this:

flex: 0, 0, calc((100% / #{$columns}) - ((#{$gutter-width} * #{$gutters}) / #{$columns}));

But once again, guess what? IE and Edge don't currently support the flex shorthand and render all over the place.

The good news is that we're using a mixin so when the day comes that flex renders in a standard cross-browser fashion we can jump in to the mixin and remove the bloat and re-compile in a matter of seconds!

Long live Sass

The beauty of all of this is that as browser compatibility improves we can keep hopping in and amending this mixin without spending hours testing (providing we always call the mixin rather than writing the raw code).

I hope I've broken this down in a way that makes sense and is helpful to anyone who stumbles across this post. If you have any questions or suggestions please let me know in the comments below.

Until next time, you sassy flexy bunch.

Darren Fisher, Creative Director at Pivale Drupal agency - a bearded man with dark hair and glasses.

Written by

Darren Fisher

Creative Director

Darren is our creative director, responsible for our design and frontend development team as well as managing the majority of our website and multisite builds. Darren is a graduate of the University for the Creative Arts, achieving a bachelor's degree in Digital Screen Arts.

Related articles

The Pivale team from left to right - Pri Scarabelli, Julie Manning, Barry Fisher, Darren Fisher, and Daniel Johnson.

Who are Pivale?

Let's talk