Christoph Gockel

Isolate CSS

02 Oct 2014

Hiding details is generally a desirable goal when developing software.

The purpose of hiding details is to increase the cohesion of parts in our software, as well as to decouple them better from each other via well defined interfaces or boundaries.

This is a well known approach when it comes to isolating ourselves from external dependencies in our code. But why only apply it for code we write for the back-end? The same abstraction principles apply no matter what external dependency we want to isolate ourselves from.

So it can and should be applied to any CSS framework we use. No matter whether we’re using Bootstrap, Pure, Less, Blueprint, 960, …

Our applications should not have any direct coupling to an external framework. There should be no CSS classes directly used that were not defined by us for our project.

For the example code I will use Yahoo!’s Pure framework. But the principles apply for any framework.

Pure provides pure-g classes to create a grid, and several pure-u-* classes as units/columns within these grids.

A grid with two buttons next to each other can be defined like this:

<div class="pure-g">
  <div class="pure-u-1-2">
    <a class="pure-button" href="/">Back</a>
  </div>
  <div class="pure-u-1-2">
    <a class="pure-button" href="/game/restart">Restart</a>
  </div>
</div>

As we can see there are many references to the classes defined by Pure. By that we have coupled the view directly to the framework we use.

Directly coupling to a framework is not always a good approach. Sounds familiar? Maybe that’s because whenever something like this happens in for example Ruby code, many developers immediately react with some sort of hesitation by introducing such a tight coupling. But even for CSS the same abstraction and isolation principles apply.

The view belongs to our application. And therefore we should isolate any external dependency from that.

It would be better if we could write the previous code in a manner that we are in charge of what CSS classes the elements use.

Something like this:

<div class="grid-container">
  <div class="half-width">
    <a class="button" href="/">Back</a>
  </div>
  <div class="half-width">
    <a class="button" href="/game/restart">Restart</a>
  </div>
</div>

This does a better job at expressing the intent of what the HTML is supposed to do.

How to achieve CSS isolation?

I used Sass to be able to use the CSS classes just shown. Using Sass allows to “extend” new selectors from existing selectors.

With this we can create new selectors for our views that match the domain of the application we’re developing.

The definition for the classes of the last example look like this:

div.grid-container {
  @extend .pure-g;
}

div.half-width {
  @extend .pure-u-1-2;
}

a.button {
  @extend .pure-button;
}

Sass will create the classes with the appropriate content for us. So div.grid-container will have the same declarations as .pure-g has.

This is not only possible for single classes, though. Also multiple usages of classes can be merged together.

A button that is coloured in Pure’s primary colour is declared like that for example:

<button type="submit" class="pure-button pure-input-1 pure-button-primary">Play!</button>

With a SCSS declaration like this:

button.play-game {
  @extend .pure-button, .pure-input-1, .pure-button-primary;
}

We are now able to declare the button with better expressed intent:

<button type="submit" class="play-game">Play!</button>

What does that tell us?

By isolating from the CSS framework we do not couple our views to any specific framework anymore.

When we want to switch to another framework, we do not have to update all the views. We only have to update the abstraction layer between our views and the framework. And in this case, the abstraction layer is the SCSS file. It’s likely to be easier to maintain just that file instead of finding all usages of framework specific CSS classes across all existing views.

If there’s one thing to take away from that: Isolation principles are valid for every area in our applications.