Creating a Lightweight Grid System

Creating a Lightweight Grid System

View on GitHub

This post will take 3 minutes to read.

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 light­weight.

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­ur­al 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­tion­al 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 giv­en neg­at­ive left and right mar­gin to account for the left and right pad­ding each of the columns are giv­en (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 oth­er 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­vidu­al 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 with­in 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 easi­er 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­i­ar 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?

Tweet this

14 Comments

  1. Sridevi

    Simple and inform­at­ive con­tent. Thank you. Normally I am scared of grids even­though they say it’s simple. But your explan­a­tion is refresh­ing.

  2. Niven

    Great piece. I’ve nev­er been sold on grids, mainly because of the lack of mobile first point you made. I’ve seen a few bad imple­ment­a­tions that have put me off. This how­ever has got me inter­ested again. Thanks!

  3. VaughanJ

    Why do grid frame­works have to be so com­plic­ated?! THIS is a simply per­fect base to begin with! Thank you so much for shar­ing.

  4. Alex

    Hey Josh,

    this looks awe­some. I have to give this a try. Much bet­ter for smal­ler sites than a bloated frame­work like Bootstrap or Foundation. Earlier this year, I’ve come across a simple grid solu­tion cre­ated by David Bushell, but yours seems even more light­weight. Great work!

    Cheers,
    Alex

  5. Doddi

    Looks good Josh. Simple and eas­ily adjustable if needed. I was usind 34grid till now but will give your solu­tion a try as I am build­ing my new port­fo­lio site these days. Thanks!

  6. Doddi

    Just one more note from me: I will prob­ably change nam­ing syn­tax to some­thing like grid50, grid60 etc. as your pro­pos­al looks too over­com­pla­cated to me. But that’s just a detail.

  7. ipaas

    great tech­nique and nice to see you post­ing after a while!

    until flexbox will be widely sup­por­ted, i’m a great fan of using inline blocks over float­ing ele­ments in lay­outs. as you’ve men­tioned the notori­ous white space issue, i’ve come up with anoth­er approach to tackle it: http://jsfiddle.net/ipaas/H69aZ/2/

    i’m using rem-units to reset the con­tain­ing ele­ments’ font-size instead of pixels to reflect root element’s dif­fer­ent font size across medi­aquer­ies. leg­acy ie’s would require either a poly­fill or a sim­pler tar­geted pixel val­ues set.

  8. Andrew

    What if you want the columns to stay on widths below 40em?

    I have an addi­tion­al class for small columns, so both these classes are added to the ele­ment:
    .col-sml-50
    .col-50

    However it means I’m repeat­ing the declar­a­tions for those classes. Any idea of a bet­ter way?
    Maybe a .pre­serve-cols class or some­thing?

  9. Josh

    Andrew, if you want to add that func­tion­al­ity then I would sug­gest mov­ing my code out­side of the media query and then using a ‘full width’ class and a max-width media query to select­ively enforce respons­ive columns.