5 min read

Grid systems have become an essential part of front-end web development. Whether you are building a web app or a marketing landing page, a grid system is the core of your layout. The problem I kept coming across is that grid systems are not one size fits all, so often I would have to go find a new system for each project. This led me to look for a way to avoid this search, which lead me to this solution. Thanks to some of SASS’s functionality, we can actually create a grid system we can reuse and customize quickly for every project.

Getting Started

We’re going to start out by setting up some variables that we will need to generate our grid system:

$columnCount: 12;
$columnPadding: 20px;
$gridWidth: 100%;
$baseColumnWidth: $gridWidth / $columnCount;

$columnCount will do just what it says on the tin, set the number of columns for our grid layout. $columnPadding sets the spacing between each column as well as our outside gutters.$gridwidth sets how wide we want our layout to be. This can be set to a percentage for a fluid layout or another unit (such as px) for a fixed layout. Finally, we have $baseColumnWidth, which is a helper variable that determines the width of a single column based on the total layout width and the number of columns.

We are going to finish our initial setup by adding some high-level styles:

*, *:before, *:after {
   box-sizing: border-box;
}
img, picture {
   max-width: 100%;
}

This will set everything on our page to use box-sizing: border-box, making it much easier to calculate our layout since the browser will handle the math of deducting padding from our widths for us. The other thing we did was make all the images in our layout responsive, so we set a max-width: 100% on our image and picture tags.

Rows

Now that we have our basic setup done, let’s start crafting our actual grid system. Our first task is to create our row wrapper:

.row {
   width: $gridWidth;
   padding: 0 ( $gutterWidth / 2 );
  
   &:after {
       content: "";
       display: table;
       clear: both;
   }
}

Here we set the width of our row to the $gridWidth value from earlier. For this example, we are using a fully fluid width of 100%, but you could also add a max-width here in order to constrain the layout on larger screens. Next, we apply our outside gutters by taking $gutterWidth and dividing it in half. We do this because each column will have 10px of padding on either side of it, so that 10px plus the 10px we are adding to the outside of the row will give us our desired 20px gutter. Lastly, since we will be using floats to layout our columns, we will clear them after we close out each row.

One of the features I always require out of a grid-system is the ability to create nested columns. This is the ability to start a new row of columns that is nested within another column. Let’s modify our row styling to accommodate nesting:

.row {
   width: $gridWidth;
   padding: 0 ( $gutterWidth / 2 );
  
   &:after {
       content: "";
       display: table;
      clear: both;
   }
   .row {
       width: auto;
       padding: 0 ( $gutterWidth / -2 );
   }
}

This second .row class will handle our nesting. We set width: auto so that our nested row will fill its parent column, and to override a possible fix width that could be inherited from the original unnested .row class. Since this row is nested, we are not going to remove those outside gutters. We achieve this by taking our $gutterWidth value and divide it by -2, which will pull the edges of the row out to compensate for the parent column’s padding. This will now let us nest till our heart’s content.

Columns

Columns are the meat of our grid system. Most of the styles for our columns will be shared, so let’s create that block first:

[class*="column-"] {
   float: left;
   padding: 0 ( $columnPadding / 2 );
}

Using a wildcard attribute selector, we target all of our column classes, floating them left and applying our familiar padding formula. If [browser compatibility] is a concern for you, you can also make this block a placeholder and @extend it from your individual column classes.

Now that we have that out of the way, it’s time for the real magic. To generate our individual column styles, we will use a SASS loop that iterates over $columnCount:

@for $i from 1 through $columnCount {
   .column-#{$i} {
       width: ( $baseColumnWidth * $i) ;
   }
}

If you are familiar with JavaScript loops, then this code shouldn’t be too foreign to you. For every column, we create a .column-x block that will span X number of columns. The #{$i} at the end of the class name prints out i to create each columns class name. We then set its width to $baseColumnWidth times the number of columns we want to span (represented by i). This will loop for the number of columns we set $columnCount. This is the core of what makes this pattern so powerful, as no matter how many or few columns we need this loop will generate all the necessary styles.

This same pattern can be extended to make our grid-system even more flexible. Let’s add the ability to offset columns to the left or right by making the following modifications:

@for $i from 1 through $columnCount {
   .column-#{$i} {
       width: ( $baseColumnWidth * $i) ;
   }
   .prepend-#{$i} {
       margin-left: ( $baseColumnWidth * $i);
   }
   .append-#{$i} {
       margin-right: ( $baseColumnWidth * $i );
   }
}

This creates two new blocks on each iteration that can be used to offset a row by X number of columns to the left or right.

Plus, because you can have multiple loops, you can also use this pattern to create styles for different breakpoints:

@media only screen and (min-width: 768px) {
   @for $i from 1 through $columnCount {
       .tablet-column-#{$i} {
           width: ( $baseColumnWidth * $i) ;
       }
       .tablet-prepend-#{$i} {
           margin-left: ( $baseColumnWidth * $i);
       }
       .tablet-append-#{$i} {
           margin-right: ( $baseColumnWidth * $i );
       }
   }
}

Conclusion

We now have a full-featured grid system that we can customize for individual use cases by adjusting just a few variables. As technologies and browser support changes, we can continue to modify this base file including support for things like flex-box and continue to use it for years to come. This has been a great addition to my toolbox, and I hope it is to yours as well.

About The Author

Brian is a Front-End Architect, Designer, and Product Manager at Piqora. By day, he is working to prove that the days of bad Enterprise User Experiences are a thing of the past. By night, he obsesses about ways to bring designers and developers together using technology. He blogs about his early stage startup experience at lostinpixelation.com, or you can read his general musings on twitter @b_hough.

LEAVE A REPLY

Please enter your comment!
Please enter your name here