Objects in CSS

Oxygen is an object-oriented system for CSS.[1] You are probably already familiar with objects, but you may not be used to seeing them in your CSS. Objects in the technical sense are the nouns of a system. If you recall first-grade English, you will remember that a noun is a person, place, or thing. In CSS, objects are the individual parts that make up a web page or application. Let’s look at an example.

Here is a mockup of a web application with several of the individual objects called out:

Diagram of application with objects highlighted

As you can see, objects are things like logos, buttons, textboxes, headers, icons, and sparklines. All of the parts that make up a user interface.

Sharp-shooting with CSS selectors

The traditional way of thinking about CSS teaches you to style a document almost entirely in terms of selectors. Selectors are the first part of any rule in CSS. The part of the rule that targets a set of elements on a web page:

.sidebar > ul > li:last-child {
  border-bottom: none;
}

In the example above, the first line up until the opening curly brace ({) defines the selector for this CSS rule. Reading backwards from right to left, this selector targets the last <li>, directly inside of a <ul>, directly inside of an element with the class of “sidebar”.

Selectors like this one give us the precision of a sharp-shooter for targeting specific elements with specific styles.

Long selectors, and their woes

CSS is a very concise language. It allows us to pack a lot of power into a small amount of code. To see what I mean, let’s unpack the rule in the above using a little pseudo code. Here’s how the logic of the selector breaks down in a series of if statements:

If the element is the last child of the parent element then:
  If element is an <li> element then:
    If the parent element is a <ul> then:
      If the parent of the parent element has a class of "sidebar" then:
        Set bottom-border to none.
      End If
  End If
End If

There is so much power wrapped up in this one selector! There are at least four conditionals here. Selectors that go through several levels like this one can be hard to understand. Things that are hard to understand can be hard to debug.

Now the selector above isn’t that hard to understand on its own. But imagine what happens when you combine it with 3-4 other selectors that also target the same element in different ways. Which selector wins?

When an entire project is made up of long selectors, debugging can be a nightmare. Long, highly-specific selectors are the source of more problems in CSS than any other single aspect of the language. Don’t get me wrong. I’m glad that CSS has this kind of power. It’s just far to easy to shoot yourself in the foot when long selectors are the norm on a project.

For this reason alone, long selectors should be thought of as red flags and avoided.[2]

Learning to think in objects

While long selectors are hard to understand and debug, there’s another reason to avoid them: they obscure the underlying objects in our CSS.

To extend our previous example:

.sidebar > ul {
  list-style: none;
}
.sidebar > ul > li {
  border-bottom: 1px solid silver;
  margin: 0;
}
.sidebar > ul > li:last-child {
  border-bottom: none;
}
.sidebar > ul > li > a {
  display: block;
  padding: 5px 10px;
  text-decoration: none;
}

Here we have three CSS rules that effectively style the navigation of our site. Why not use names in our CSS that make this more apparent?

.nav {
  list-style: none;
}

.nav-item {
  border-bottom: 1px solid silver;
  margin: 0;
}
.nav-item:last-child {
  border-bottom: none;
}

.nav-item-link {
  display: block;
  padding: 5px 10px;
  text-decoration: none;
}

With these changes we’ve used classes to create unique names for each of the elements that make up our navigation. Now it is immediately obvious that we are working with three different objects in our CSS:

  • The outer “nav” wrapper
  • Each individual “nav-item”
  • And the “nav-item-link”

Also of note, we’ve gotten rid of those mangled, long selectors that make CSS difficult to read and debug. The objects that we are working with are now front and center.[3]

Optimize for clarity

There’s a small nugget of wisdom in this chapter that deserves a little more attention. Sometimes we get so wrapped up in what we are building that we forget to stop and ponder how we are building! The question that you should ask yourself is not just, have I accomplished what I set out to do? But, have I done it in a way that is easy to understand and extend?

CSS is a language with a lot of power. If you are not careful, you can do more harm in a few lines of code, than good. CSS is code. And like all code it is important to think about how it will be used and extended in the future.

Don’t fall into the trap of thinking that you are only coding for yourself. More often than not the code that you write today will be used and extended by someone else tomorrow. The patterns that you lay down will become the foundation that others build upon. The next time you are congratulating yourself on writing a clever bit of CSS, think about whether others will be able to understand it later. (Or for that matter, whether you will be able to understand it! I often come back to code I’ve written months or years afterward and wonder what I was thinking at the time!)

Strive to make your code easy to understand and extend. Optimize for clarity.

In summary

Let’s generalize what we’ve learned in this chapter into three easy-to-remember principles:

  1. Long selectors are red flags and should be avoided if possible
  2. Learn to think about objects in your code, not just selectors
  3. Make your code easy to understand and extend

In the next chapter, we’ll look at some handy naming conventions that will make all of this much easier.


  1. Oxygen borrows heavily from Object-Oriented Programming for it’s terminology. ↩︎

  2. Long selectors are also responsible for negative performance issues, but I’d argue that the main reason to avoid them is that they make code hard to understand and extend. ↩︎

  3. The astute reader will notice that Oxygen’s approach to CSS leads to an explosion of classes in our HTML. Doesn’t this violate DRY? My goal with Oxygen is to articulate a style of coding CSS that is easy to understand and extend. It is true that the Oxygen naming conventions do this at the expense of the HTML, but the clarity that is gained in code considered worth that price. To put it another way: Oxygen exchanges complexity in CSS for verbosity in HTML markup. In practice, this leads to CSS that is much easier to maintain. ↩︎

Subscribe to the Oxygen newsletter to be notified as chapters are written!

Discussion