Creating Your Own CSS Grid System

CSS Grids have been around a long time. Often they come bundled in frameworks such as Bootstrap. I'm not a Bootstrap hater, but sometimes using a framework is overkill if all you really need is a grid. Here's how to make your own CSS Grids from scratch.

The elements of a CSS Grid

As we can see, the basic grid contains just a few elements.

  • a container
  • rows
  • columns
  • gutters (the space between columns)

The Container

The purpose of the container is to set the width of the entire grid. The width of the container is generally 100%, but you might want to set a max-width for larger displays.

    .grid-container {
        width : 100%;
        max-width : 1200px; 
    }

The Row

The purpose of the row element is to keep the columns inside it from overflowing onto other rows. To achieve this, we'll use the clearfix hack to make sure everything inside the row stays inside the row.

    /*-- our cleafix hack -- */ 
    .row:before, 
    .row:after {
        content:"";
        display: table ;
        clear:both;
    }

The Column

The column is definitely the most complicated part of the grid. First off, there are several different ways of positioning columns in CSS, then there are various widths to consider, as well as factors like responsive design. In this tutorial we'll be positioning the columns and giving them widths. I'll leave the responsive bit for next time.

Column Positioning

Floats, inline-blocks, display-table, display-flex. These are all different ways of positioning columns in CSS. From my personal experience, the least error prone and most widely used of these methods is the 'float' method. If our columns are empty however, our floated columns will stack on top of each other. To prevent this, we'll give our columns a min-height of 1px as well as float them.

    [class*='col-'] {
        float: left;
        min-height: 1px; 
    }

Column Widths

To find the width of one column, all we have to do is divide the total number of columns by the width of the container. In our case, the width of the container is 100%, and we want 6 columns, so 100/6 = 16.66, so our base column width is 16.66%.

    [class*='col-'] {
        float: left;
        min-height: 1px; 
        width: 16.66%; 
    }

This of course, is just the beginning. If we want a section that's 2 columns wide, we have to create an 2-column-wide column. The calculations are pretty simple.

    .col-1{
        width: 16.66%; 
    }
    .col-2{
        width: 33.33%; 
    }
    .col-3{
        width: 50%; 
    }
    .col-4{
        width: 66.664%;
    }
    .col-5{
        width: 83.33%;
    }
    .col-6{
        width: 100%;
    }

The only thing we have consider when using these column combinations is that the total number of columns in a row adds up to 6 (or whatever the total number of columns is).

Column Gutters

Before the 'border-box' box-sizing model, giving percentage-width elements a static padding was a real pain. Luckily, using the 'border-box' model, we can create gutters with ease.

    /*-- setting border box on all elements inside the grid --*/
    .grid-container *{
        box-sizing: border-box; 
    }

    [class*='col-'] {
        float: left;
        min-height: 1px; 
        width: 16.66%; 
        /*-- our gutter --*/
        padding: 12px;
    }

(Personally, I use * {box-sizing: border-box;} in my CSS to apply border-box to everything on the page).

Our basic Grid is ready:

<div class="grid-container outline">
    <div class="row">
        <div class="col-1"><p>col-1</p></div> 
        <div class="col-1"><p>col-1</p></div> 
        <div class="col-1"><p>col-1</p></div> 
        <div class="col-1"><p>col-1</p></div> 
        <div class="col-1"><p>col-1</p></div> 
        <div class="col-1"><p>col-1</p></div> 
    </div> 
    <div class="row">
        <div class="col-2"><p>col-2</p></div> 
        <div class="col-2"><p>col-2</p></div> 
        <div class="col-2"><p>col-2</p></div> 
    </div> 
    <div class="row">
        <div class="col-3"><p>col-3</p></div> 
        <div class="col-3"><p>col-3</p></div> 
    </div> 
</div>

The entire HTML & CSS needed to create the above grid:

CSS

    .grid-container{
        width: 100%; 
        max-width: 1200px;      
    }

    /*-- our cleafix hack -- */ 
    .row:before, 
    .row:after {
        content:"";
        display: table ;
        clear:both;
    }

    [class*='col-'] {
        float: left; 
        min-height: 1px; 
        width: 16.66%; 
        /*-- our gutter -- */
        padding: 12px; 
        background-color: #FFDCDC;
    }

    .col-1{ width: 16.66%; }
    .col-2{ width: 33.33%; }
    .col-3{ width: 50%;    }
    .col-4{ width: 66.66%; }
    .col-5{ width: 83.33%; }
    .col-6{ width: 100%;   }

    .outline, .outline *{
        outline: 1px solid #F6A1A1; 
    }

    /*-- some extra column content styling --*/
    [class*='col-'] > p {
     background-color: #FFC2C2; 
     padding: 0;
     margin: 0;
     text-align: center; 
     color: white; 
    }

HTML

    <div class="grid-container outline">
        <div class="row">
            <div class="col-1"><p>col-1</p></div> 
            <div class="col-1"><p>col-1</p></div> 
            <div class="col-1"><p>col-1</p></div> 
            <div class="col-1"><p>col-1</p></div> 
            <div class="col-1"><p>col-1</p></div> 
            <div class="col-1"><p>col-1</p></div> 
        </div> 
        <div class="row">
            <div class="col-2"><p>col-2</p></div> 
            <div class="col-2"><p>col-2</p></div> 
            <div class="col-2"><p>col-2</p></div> 
        </div> 
        <div class="row">
            <div class="col-3"><p>col-3</p></div> 
            <div class="col-3"><p>col-3</p></div> 
        </div> 
    </div>

<hr/>

Part 2: Making Our Grid Responsive

Adjusting our grid for mobile layouts is pretty easy. All we have to do is adjust the widths of the columns.

For simplicities sake, I'm going to double the widths of the columns for screens under 800px.

The only thing to watch out for is a few exceptions where the last column in the row hangs off the end. Such as in the case of the .col-2 columns and the .col-1 beside the .col-5 column.
To counter this, we'll make the last .col-2 and .col-1 in the row 100% wide.

    @media all and (max-width:800px){
        .col-1{ width: 33.33%;  }
        .col-2{ width: 50%;     }
        .col-3{ width: 83.33%;  }
        .col-4{ width: 100%;    }
        .col-5{ width: 100%;    }
        .col-6{ width: 100%;    }

        .row .col-2:last-of-type{
            width: 100%; 
        }

        .row .col-5 ~ .col-1{
            width: 100%; 
        }
    }

For screens that are even smaller than 800px, we'll make all the columns except the very smallest 100%.

    @media all and (max-width:650px){
        .col-1{ width: 50%;     }
        .col-2{ width: 100%;    }
        .col-3{ width: 100%;    }
        .col-4{ width: 100%;    }
        .col-5{ width: 100%;    }
        .col-6{ width: 100%;    }
    }

And that's all there is too it. We've now created our very own responsive grid system, without using a framework.

<div class="grid-container outline">
    <div class="row">
        <div class="col-1"><p>col-1</p></div> 
        <div class="col-1"><p>col-1</p></div> 
        <div class="col-1"><p>col-1</p></div> 
        <div class="col-1"><p>col-1</p></div> 
        <div class="col-1"><p>col-1</p></div> 
        <div class="col-1"><p>col-1</p></div> 
    </div> 
    <div class="row">
        <div class="col-2"><p>col-2</p></div> 
        <div class="col-2"><p>col-2</p></div> 
        <div class="col-2"><p>col-2</p></div> 
    </div> 
    <div class="row">
        <div class="col-3"><p>col-3</p></div> 
        <div class="col-3"><p>col-3</p></div> 
    </div> 
    <div class="row">
        <div class="col-4"><p>col-4</p></div> 
        <div class="col-2"><p>col-2</p></div> 
    </div> 
    <div class="row">
        <div class="col-5"><p>col-5</p></div> 
        <div class="col-1"><p>col-1</p></div> 
    </div> 
    <div class="row">
        <div class="col-6"><p>col-6</p></div> 
    </div> 
</div>

Be warned though, that this guide is just a starting point for creating your own system. It is not a framwork or even a complete solution, but I hope it does demystify the process of creating a CSS grid a bit.