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 structure of a website, the first thing I like to sort out is the underlying grid system. There are a large number of available grid systems out there, but not many that are responsive (preferably mobile-first) and nestable while remaining extremely lightweight.

With this in mind I set out to create a fairly simple grid system that would be suitable for the majority of my projects while also meeting the above requirements. The finished 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 system is mobile-first, I want the block-level elements I’m using for the grid to take up their natural width (100%) on narrow devices. I’ve therefore wrapped the whole lot in a media query. This means that the grid won’t kick in until the viewport is at least 40em wide. Keep in mind that the width that the grid should start working at depends on the content; 40em is just a rough guide. I chose not to use any additional media queries as they are tied directly to the content. Most projects should work with a single breakpoint but if you need more then make sure to add them.

.grid {
    margin: 0 -0.75em;
}

The .grid element is given negative left and right margin to account for the left and right padding each of the columns are given (i.e. the column’s gutter). That way, when using the grid as part of a page, it will still appear as wide as the other block-level elements above and below. I’m basing the gutter width on the standard baseline height that I use for most projects (1.5em), but feel free to adjust this to suit your individual 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 themselves sit side-by-side with the use of inline-block. See this article to learn why I prefer to use inline-block as opposed to floats when laying out a website. I am using box-sizing: border-box; to ensure that the padding is contained within the column’s width.

It is well known that using inline-block renders the white space between inline-block elements. There are a few ways to handle this, but the most reliable is to comment out the white space between inline-block elements in the markup. Here is an example of what I’m talking about:

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

Now, in terms of nesting, the only thing I need to take care of is any unwanted padding and margin. This is pretty easy; I simply remove the margin and padding from any column that also has a class of grid.

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

A demonstration of the nesting can be found here.

Finally, I added a bunch of preset 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 alternative naming system for column widths I decided to use the exact percentage value. I feel that this makes it easier to use overall as there is no learning curve. I’m also using BEM syntax, and for those that are unfamiliar with what that is, check out this article.

Finally, I’ve also converted the grid system from CSS to SCSS. That code can be found here.

I’d love to hear your thoughts and feedback. Anything obvious that I’ve missed?

Tweet this

14 Comments

  1. Sridevi

    Simple and informative content. Thank you. Normally I am scared of grids eventhough they say it’s simple. But your explanation is refreshing.

  2. Niven

    Great piece. I’ve never been sold on grids, mainly because of the lack of mobile first point you made. I’ve seen a few bad implementations that have put me off. This however has got me interested again. Thanks!

  3. VaughanJ

    Why do grid frameworks have to be so complicated?! THIS is a simply perfect base to begin with! Thank you so much for sharing.

  4. Alex

    Hey Josh,

    this looks awesome. I have to give this a try. Much better for smaller sites than a bloated framework like Bootstrap or Foundation. Earlier this year, I’ve come across a simple grid solution created by David Bushell, but yours seems even more lightweight. Great work!

    Cheers,
    Alex

  5. Doddi

    Looks good Josh. Simple and easily adjustable if needed. I was usind 34grid till now but will give your solution a try as I am building my new portfolio site these days. Thanks!

  6. Doddi

    Just one more note from me: I will probably change naming syntax to something like grid50, grid60 etc. as your proposal looks too overcomplacated to me. But that’s just a detail.

  7. ipaas

    great technique and nice to see you posting after a while!

    until flexbox will be widely supported, i’m a great fan of using inline blocks over floating elements in layouts. as you’ve mentioned the notorious white space issue, i’ve come up with another approach to tackle it: http://jsfiddle.net/ipaas/H69aZ/2/

    i’m using rem-units to reset the containing elements’ font-size instead of pixels to reflect root element’s different font size across mediaqueries. legacy ie’s would require either a polyfill or a simpler targeted pixel values set.

  8. Andrew

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

    I have an additional class for small columns, so both these classes are added to the element:
    .col-sml-50
    .col-50

    However it means I’m repeating the declarations for those classes. Any idea of a better way?
    Maybe a .preserve-cols class or something?

  9. Josh

    Andrew, if you want to add that functionality then I would suggest moving my code outside of the media query and then using a ‘full width’ class and a max-width media query to selectively enforce responsive columns.