Semantic grids with Sass Loops and Silent Placeholders

Grid frameworks and boilerplates often get a bad rap and certainly one of the things high up on the list of moans and groans is the HTML and CSS that they force you to use generate:

12-devs-article-fig-1

With the rapid adoption of box-sizing:border-box it’s now pretty straightforward to make your own grid that is right for your content – which is great!

However, there’s still the issue of writing code that’s readable, maintainable and the ever present difficulty of naming things so they communicate purpose and meaning rather than being purely “presentational” both in function and in name.

The goal of this article is to provide a suggestion for a simple, maintainable solution to writing your own grid components for responsive design whilst keeping in mind the need for “semantic class names” and developer friendly code.

I use the term “semantic class names” in big air quotes because really the term is a bit meaningless. There’s a great quote from
CSS-Guidelines by Harry Roberts that says:

Remember: classes are neither semantic or insemantic; they are
sensible or insensible! Stop stressing about ‘semantic’ class
names and pick something sensible and futureproof.

The important point here is that the terminology we use is really irrelevant but the naming conventions we choose should be sensible and convey meaning and intent – we want there to be as little confusion to our fellow developers as possible. So when I talk about “semantic class names” I use it as a short hand for “class names that are sensible and convey meaning”. After all the word semantic seems to hold some kind of hidden meaning in the web community. Ironically.

Right, enough bickering over semantics: let’s dive in…

Sass-in’ it up

Our first step towards creating an easy to write and easy to use grid is to use Sass.

Sass is a CSS-preprocessor that puts the maintainable back into
“maintainable CSS” and makes writing CSS fun again. A full introduction to Sass is outside the scope (and word count) of this article so I suggest you reach for your favourite search engine if you want to find out more or get your head around the basics.

Let’s look at a couple of features of Sass that might be able to help us in our quest.

A variety of various variables

With Sass we can declare variables that define our grid which can keep things a little more human readable:

$sidebar-width: 33.333%;
$main-content-width: 66.667%;

.sidebar {
    width: $sidebar-width;
}
.main-content {
    width: $main-content-width;
}

The Sass variables (declared with the $ sign) allow us to attach a label to an arbitrary value – a number in this case. This is great but it’s a bit limiting and could lead to confusion. If we wanted something else to have this two-thirds:one-third relationship, we probably don’t want to use this method of naming:

.contact-form {
    label {
        width:$sidebar-width;
    }
    input[type=text],
    input[type=email] {
        width:$main-content-width;
    }
}

This would compile down to give the contact form label a width of 33.333% and the inputs a width of 66.667% which is the desired ratio of widths (hypothetically), but the variable naming doesn’t make any sense. We’ve made our code less human readable!

If we make re-usable components then Sass can help us to write
readable, maintainable code and keep things DRY (don’t repeat yourself).

How about this?

$grid-1-of-3: (1/3) * 100%; // 33.333%
$grid-2-of-3: (2/3) * 100%; // 66.667%
$grid-3-of-3: (3/3) * 100%; // 100%

Here we use some a nice simple naming convention and hammer home the point by actually showing the mathematical calculation behind our values. Most people will recognise that 33.3% is one third but would you recognise 83.3% as being 20/24? Possibly but less likely – so demonstrating the sums is a useful trick.

Now we have some more useful variables, we can then use them in multiple places:

.container {
    width: $grid-3-of-3;
    max-width: 1000px;
}
.sidebar {
    width:$grid-1-of-3;
}
.main-content {
    width:$grid-2-of-3;
}
.contact-form {
    label {
        width:$grid-1-of-3;
    }
    input[type=text],
    input[type=email] {
        width:$grid-2-of-3;
    }
}

We’ve made a basic grid and given it some sense with clever naming. Amazing. However, this example was simple, with only 3 columns – what if you wanted to create a 12 column grid or 24 column grid, or 100 column grid? You might think you’d have to do a lot of typing and get tired fingers, but Sass has you covered.

Looping the loop

Loops are one of my favourite features of Sass because I’m (proud to be) a lazy developer. I can’t stand doing things over and over again – I like things to be simple and efficient.

We can create a 100 column grid in just 10 lines of code – one
assumption is being made here: that you are using * { box-sizing:border-box }

[class^=grid-] {
    float:left;
    margin:0;
    padding:0 2%; // gutters
}
@for $i from 1 through 100 {

    .grid-#{$i}-of-100 {
        width: ($i / 100) * 100%;
    }
}

First we set some common styles for any class that starts with grid- then we use a @for loop to generate 300 lines of CSS with Sass.

$i is a counter variable that starts at 1 and each time the loop runs, is incremented by 1 until $i is equal to 100. The through means up to an including; if you want to go up to but not including 100, you can use the keyword to instead.

On each iteration, the value of $i is passed into the style block where it’s used in the calculation of the width and also interpolated in the class name where you see #{$i}.

This will generate code like the following:

.grid-1-of-100 { width:1%; } // $i is equal to 1
.grid-2-of-100 { width:2%; } // $i is equal to 2

// lots of looping until...

.grid-100-of-100 { width:100%; } // $i is equal to 100

Now, a 100 column grid where each column is 1% of the total container is perhaps not that useful but it nicely illustrates the point of how Sass can save you time.

BUT, I hear you cry: “those grid class names are little better than the kind of filth the frameworks spit out!”. And you are right. But we can fix that…

Placeholder title

Our aim is to use Sass to write less and do more – but do it more meaningfully. That’s where Sass silent placeholder classes and the extend directive come in to play.

Placeholder selectors were introduced in Sass 3.2 and can be very handy for keeping the human readable goal in check. They are defined with a % prefix but otherwise, look like any other block of style properties:

#foo {
    // styles for an ID selector
}
.foo {
    // styles for a class selector
}
%foo {
    // styles for a placeholder selector
}

The great thing about placeholder selectors is that they aren’t output into the CSS when Sass compiles. You might wonder then, how they can be used at all?

That’s where the @extend directive comes into play. This is a little complex so is probably best explained by example. But first of all, we have to understand it’s use case.

Let’s say you have an element with two absolutely positioned pseudo elements relative to it. It might be a heading with fancy swirly bits on each side. Both pseudo elements share some properties with each other but also have some differences. The style declaration might look a bit like this:

.fancy-title {
    // styles for a fancy title

    &:before,
    &:after {
        content:"";

        position:absolute;
        top:0;

        width:50px;
        height:50px;
    }
    &:before {
        right:100%;
        background:url('fancy-title-left-swirl.png');
    }
    &:after {
        left:100%;
        background:url('fancy-title-right-swirl.png');
    }
}

We are smart, lazy developers and so we group the related styles
together with a comma separated list of selectors (in this case
&:before and &:after – the ampersand is Sass syntax for “output the parent selector here” so this actually compiles to .fancy-title:before and .fancy-title:after).

In this example, it’s easy to group the shared styles together because the declarations are right next to each other. The fringe benefit is typing less but there’s also less CSS to be output which is good for performance; less CSS means less bytes which means faster downloads and happier users.

So, if this is so smart, why don’t we do it all the time? You no doubt have multiple declarations of display:block or margin:0 in your stylesheets – so, surely the best thing to do from a performance point of view is to group them all together, no?

No.

Remember, we are lazy developers and want nice Sassy, maintainable stylesheets, less thinking and more fun. Any small performance boost from possibly reduced file-size here is overwhelmingly outweighed by the maintenance (and readability) issues associated with manually grouping everything together.

This is where I get back to talking about @extend: what we’ve just dismissed because it’s too complex and unmaintainable is what @extend does.

Yup, the Sass robots will do all the hard work for you at compile time – you get all the benefits of grouping everything together without any of the headache. Awesome.

If used wisely, @extend can be very powerful. Perhaps the
only downside comes when browsing through long comma separated lists of selectors in a web inspector during debugging. There can be some specificity issues too but let’s not focus on all that negative stuff right now. Let’s look at an example:

.button {
    display:inline-block;
    padding:0.25em 1em;

    color:white;
    background:darkSlateGrey;
    border:1px solid darkSeaGreen;
    border-radius:0.25em;
    box-shadow:5px 5px 10px rgba(black, 0.3);
}

.button-large {
    font-size:2em;
    line-height:2em;
}

// sometime later in your code, perhaps in a separate _partial.scss

.button-warning {
    @extend .button;
    @extend .button-large;

    background:crimson;
    border:1px solid darkRed;
}

When compiled, .button-warning will contain all the style rules of
.button and .button-large but also have a different background and
border. This avoids having to have long chains of class names in
your HTML which helps keep your styling and markup separate.

<!-- before Sass -->
<a class="button button-large button-warning" href="#">a warning button</a>

<!-- after Sass, using @extend -->
<a class="button-warning" href="#">a warning button</a>

The above example created a whole new module out of two components and we were able to avoid cramming the markup with class names. So far, we’re winning.

In this example, we were extending real classes rather than placeholders – in this case, it’s probably a good thing as we might want to use the .button class on it’s own elsewhere. However, we can also extend placeholder classes in the same way and as they aren’t output to CSS, we can ensure that we aren’t cluttering up the stylesheet with bits and pieces that aren’t used in their own right.

So let’s bring together everything we’ve looked at so far and see if we can achieve our goal. We can use a combination of descriptively named selectors, a loop and placeholder classes to construct a wonderfully “semantic”, easy to maintain, performance boosted grid system!

Getting Griddy with it

I think there’s been enough rambling so let’s look at an example that does exactly what we’re after.

// Set the desired number of columns in a variable for flexibility

$total-columns: 24;

// Create a placeholder for the grid container

%grid-container {
    width:100%;
    max-width:1000px; // adjust to your needs
    margin:0 0 1.5em; // bit of margin bottom for vertical rythm
}

// Create a placeholder for styles common to all columns

%grid {
    float:left;
    margin:0;
    padding:0 2%; // flexible gutters thanks to box-sizing:border-box
}

// Loop through all the columns and generate the correct width
// use @extend to pull in common styles

@for $i from 1 through $total-columns {
    %grid-#{$i}-of-#{$total-columns} {
        @extend %grid;
        width: ($i / $total-columns) * 100%;
    }
}

// Now make use of the placeholders with meaningful class names

.products-page {
    @extend %grid-container;
}
.products-sidebar {
    @extend %grid-8-of-24; // 1/3 of page
}
.products-list-container {
    @extend %grid-16-of-24; // 2/4 of page

    .products-list {
        @extend %grid-container; // nested grid
    }
    .product {
        @extend %grid-6-of-24; // new grid context, each product is 1/4 of container
    }
}

There we go – we’ve managed to create a lean system of re-usable
components that will get us well on the way to building a nice fluid grid where we can use developer friendly class names and give more meaning to our code. Good work!

If you’d like to look at (and play around with working examples of) a slightly more detailed and extensible version of some of the concepts mentioned in this article, why not head over to Github and check out my CompassGrid repo.

Back to the articles