Joshua Hibbert

Latest Articles

Creating a Lightweight Grid System

Creating a Lightweight Grid System

View on GitHub

When it comes to the struc­ture of a web­site, the first thing I like to sort out is the under­ly­ing grid sys­tem. There are a large num­ber of avail­able grid sys­tems out there, but not many that are respons­ive (prefer­ably mobile-first) and nestable while remain­ing extremely lightweight.

With this in mind I set out to cre­ate a fairly simple grid sys­tem that would be suit­able for the major­ity of my pro­jects while also meet­ing the above require­ments. The fin­ished product weighs in at 0.805 kb (less than 30 lines of code) while being both mobile-first and nestable. Here it is in all its glory:

@media (min-width: 40em) {
    .grid {
        margin: 0 -0.75em;
    }
    [class*="grid__col--"] {
        display: inline-block;
        padding: 0 0.75em;
        vertical-align: top;
        -webkit-box-sizing: border-box;
           -moz-box-sizing: border-box;
                box-sizing: border-box;
    }
    .grid[class*="grid__col--"] {
        margin: 0;
        padding: 0;
    }
    .grid__col--20  { width: 20%; }
    .grid__col--25  { width: 25%; }
    .grid__col--30  { width: 30%; }
    .grid__col--33  { width: 33%; }
    .grid__col--40  { width: 40%; }
    .grid__col--50  { width: 50%; }
    .grid__col--60  { width: 60%; }
    .grid__col--67  { width: 67%; }
    .grid__col--70  { width: 70%; }
    .grid__col--75  { width: 75%; }
    .grid__col--80  { width: 80%; }
    .grid__col--100 { width: 100%; }
}

Let’s look at exactly what it is I’m doing with each part of the above code.

@media (min-width: 40em) { ... }

As this grid sys­tem is mobile-first, I want the block-level ele­ments I’m using for the grid to take up their nat­ural width (100%) on nar­row devices. I’ve there­fore wrapped the whole lot in a media query. This means that the grid won’t kick in until the view­port is at least 40em wide. Keep in mind that the width that the grid should start work­ing at depends on the con­tent; 40em is just a rough guide. I chose not to use any addi­tional media quer­ies as they are tied dir­ectly to the con­tent. Most pro­jects should work with a single break­point but if you need more then make sure to add them.

.grid {
    margin: 0 -0.75em;
}

The .grid ele­ment is given neg­at­ive left and right mar­gin to account for the left and right pad­ding each of the columns are given (i.e. the column’s gut­ter). That way, when using the grid as part of a page, it will still appear as wide as the other block-level ele­ments above and below. I’m basing the gut­ter width on the stand­ard baseline height that I use for most pro­jects (1.5em), but feel free to adjust this to suit your indi­vidual needs.

[class*="grid__col--"] {
    display: inline-block;
    padding: 0 0.75em;
    vertical-align: top;
    -webkit-box-sizing: border-box;
       -moz-box-sizing: border-box;
            box-sizing: border-box;
}

The columns them­selves sit side-by-side with the use of inline-block. See this art­icle to learn why I prefer to use inline-block as opposed to floats when lay­ing out a web­site. I am using box-sizing: border-box; to ensure that the pad­ding is con­tained within the column’s width.

It is well known that using inline-block renders the white space between inline-block ele­ments. There are a few ways to handle this, but the most reli­able is to com­ment out the white space between inline-block ele­ments in the markup. Here is an example of what I’m talk­ing about:

<div class="grid">
    <div class="grid__col--50"></div><!--
 --><div class="grid__col--50"></div>
</div>

Now, in terms of nest­ing, the only thing I need to take care of is any unwanted pad­ding and mar­gin. This is pretty easy; I simply remove the mar­gin and pad­ding from any column that also has a class of grid.

.grid[class*="grid__col--"] {
    margin: 0;
    padding: 0;
}

A demon­stra­tion of the nest­ing can be found here.

Finally, I added a bunch of pre­set column widths that should meet most needs. More can be added as required.

.grid__col--20  { width: 20%; }
.grid__col--25  { width: 25%; }
.grid__col--30  { width: 30%; }
.grid__col--33  { width: 33%; }
.grid__col--40  { width: 40%; }
.grid__col--50  { width: 50%; }
.grid__col--60  { width: 60%; }
.grid__col--67  { width: 67%; }
.grid__col--70  { width: 70%; }
.grid__col--75  { width: 75%; }
.grid__col--80  { width: 80%; }
.grid__col--100 { width: 100%; }

Rather than use an altern­at­ive nam­ing sys­tem for column widths I decided to use the exact per­cent­age value. I feel that this makes it easier to use over­all as there is no learn­ing curve. I’m also using BEM syn­tax, and for those that are unfa­mil­iar with what that is, check out this art­icle.

Finally, I’ve also con­ver­ted the grid sys­tem from CSS to SCSS. That code can be found here.

I’d love to hear your thoughts and feed­back. Anything obvi­ous that I’ve missed?