Using Object-Oriented CSS with Sass

Nicole Sullivan first introduced the world to Object-Oriented CSS (OOCSS) at Web Directions North in 2008. Since then it has emerged as one of the leading modular systems for organizing your CSS.

OOCSS is not that different from other CSS methodologies like SMACSS or BEM. All of them aim to separate content from structure by placing CSS styles in reusable modular blocks of code. In fact, I usually mix SMACSS with OOCSS. (Editors note: We've also written extensivily about Modular CSS here on The Sass Way.)

Today, I'm going to teach you the basic principles of Object-Oriented CSS. I'll even throw in a bit of advice about how to do this in the most efficient way with Sass.

What is an object?

“It's a repeating visual pattern, that can be abstracted into an independent snippet of HTML, CSS and possibly JavaScript.” - Nicole Sullivan

Abstraction is the very first thing you have to consider when buildin a CSS object. What is the best way to separate out and organize the code? Nicole Sullivan (who created OOCSS) defined two main principles:

  • Separate structure and skin: You should keep the structure and positioning in a base object and the visual features (like background or border) in extender clases. This way you'd never have to overwrite visual properties.
  • Separate container and content: Never mimic the structure of your HTML in CSS. In other words, don't refer to tags or IDs in your stylesheets. Instead, try to create and apply classes that describe the use of the tag in question. And keep nested classes to a bare minimum.

Let's do a quick example

Applying these principles can be difficult at first. Let's see how this would work in a real piece of code like this one:

/* The bad way */
.box-1 {
  border: 1px solid #ccc;
  width: 200px;
  height: 200px;
  border-radius: 10px;
}
.box-2 {
  border: 1px solid #ccc;
  width: 120px;
  height: 120px
  border-radius: 10px;
}

If you look closely you will notice that we are repeating a few valuable pieces of information. In this case, the border styles are duplicated in both class definitions. So if we had to change the border-radius or border properties we would need to check all the places where we used this combination of properties.

To fix this, we can abstract the visual properties into another class.

/* The good way */
.box-1 {
  width: 200px;
  height: 200px;
}
.box-2 {
  width: 120px;
  height: 120px;
}
.box-border{
  border: 1px solid #CCC;
  border-radius: 10px;
}

Now we can apply these classes to our HTML elements, combining them to create extended objects.

<div class="box-1 box-border">Lorem ipsum</div>
<div class="box-2 box-border">Lorem ipsum</div>

What about semantics and upkeep?

You shouldn't care about being non-semantic. I care about what it means to upkeep. For example, the previous CSS would look like this in HTML.

The only way to make objects in plain CSS is to define non-semantic classes. However, this comes with some problems:

  • We have to change our HTML almost every time we need to change styles.
  • There's not a safe way to access some of the DOM elements.

Besides the unmaintainable HTML, everything else about OOCSS is just great. Our CSS code is scalable and easy to mantain and reusing our abstract classes makes it easy to style new content.

So we code the parts in CSS and extend them in HTML. Could it get any better?

Sass comes into play

I'm sure you've heard about Sass' @extend directive and of course you know how it works. So, thanks to placeholder selectors we can extend in Sass, creating semantic classes in CSS, solving our problem for HTML.

We must use placeholders as objects, and define classes formed only by merging them through @extend. This will result in an incredibly DRY CSS code. Let's see an example:

/* The bad way */
a.twitter {
  min-width: 100px;
  padding: 1em;
  border-radius: 1em;
  background: #55acee
  color: #fff;
}
span.facebook {
  min-width: 100px;
  padding: 1em;
  border-radius: 1em;
  background: #3b5998;
  color: #fff;
}

Applying all we've seen and using @extend to mix base objects we can get clean object-oriented CSS which is very easy to maintain and we don't have to change the HTML all the time.

/* The best way */
%button {
  min-width: 100px;
  padding: 1em;
  border-radius: 1em;
}
%twitter-background {
  color: #fff;
  background: #55acee;
}
%facebook-background {
  color: #fff;
  background: #3b5998;
}

.btn {
  &--twitter {
    @extend %button;
    @extend %twitter-background;
  }
  &--facebook {
    @extend %button;
    @extend %facebook-background;
  }
}

This produces efficient code that we can use easily in our HTML:

<a href="#" class="btn--twitter">Twitter</a>
<a href="#" class="btn--facebook">Facebook</a>

Pretty semantic, right? Sass has solved our problem. Remember: extend and collect non-semantic parts on Sass if you want to keep a semantic, easy to maintain HTML.

I like to call this OOSass, because it's a mixture between OOCSS and Sass and the objects are built on the Sass side. But of course, you don't have to use it. You can stick with regular OOCSS if you don't mind non-semantic HTML code. To each his own. How do you structure your CSS nowadays?

October 26, 2014 ~ Intermediate, Jaime Caballero