Oxygen naming conventions

Naming is hard. A good name for an object is difficult to find. For Oxygen I’ve created a few naming conventions that will guide you as you choose names for objects and assemble them into working web pages. Understanding the Oxygen naming conventions will also make it easier for you to read and write code that is written in the Oxygen style.

Oxygen is almost entirely a class-based system. It encourages you to use simple class-based selectors for nearly everything (there are a few exceptions). Simple class-based selectors make it easy to spot the objects in our code.

Oxygen separates class names into four basic categories:

  1. Objects
  2. Subclasses
  3. Child-objects
  4. Modifiers: State modifiers and attribute modifiers

Objects

The first and most basic part of the Oxygen system is the object. We have already covered objects in detail in the previous chapter. Let’s look at another example. Suppose we wanted to style a button like this:

When we declare objects in our CSS this is known as an object definition. Using Sass, we can write an object definition for the button above in this way:1

.button {
  background: none;
  border-radius: 3em;
  border: 3px solid #67cef4;
  color: #67cef4;
  cursor: pointer;
  font-family: "Source Sans Pro", sans-serif;
  font-size: 100%;
  padding: 0.7em 1.25em;

  &:active {
    color: #67cef4;
    background: #e8f7fd;
  }
}

This simple definition defines styles for a rounded button with a border. All of the rules for an object definition should be grouped together in one place in your CSS.

I used Sass’s parent selector (the ampersand) in this example to make it easy nest the active state in the same object definition.2 This is a handy trick for tightly associating several rules with one object.

Class-based selectors aren’t the only way to declare objects in CSS, but Oxygen encourages you to use class-based selectors because they make objects more obvious.

Subclasses

What if we wanted to have a different style for the preferred action button in a dialog? Instead of a white button blue border, perhaps a reversed button could indicate the preferred action?

In object-oriented terminology when an object is a kind of another object it is called a subclass. To create a subclass in CSS you create a new object definition:

.primary-button {
  color: white;
  background: #67cef4;
  font-weight: bold;
}

Then, in the markup you apply both classes to the subclass:

<button class="button primary-button">Okay</button>
<button class="button">Cancel</button>

This achieves exactly what we want. The primary button receives all of the styles we already defined for regular buttons and overrides just the properties that are specific to the subclass.

Child-objects

To continue our example, suppose that we now need to create a button that displays a dropdown menu and want to display a small down triangle icon inside of the button to indicate that it has a menu.

To achieve this, we can add the following object definition:

.button-caret {
  border: 0.4em solid transparent;
  border-top-color: #67cef4;
  border-bottom: 0.25em;
  display: inline-block;
  height: 0;
  width: 0;
}

With this additional rule, our HTML would need to look something like this:

<button class="button">
  Dropdown
  <i class="button-caret"></i>
</button>

Here we’ve added a child element “button-caret.” Notice that we’ve included the name of the “button” object in the name of the child object as well. When an object should only ever be used inside of another object, the Oxygen naming convention is to include the name of the parent in the name of the child. This makes it immediately obvious that the object is a child object and avoids conflicts with similarly named objects.

State modifiers

We are beginning to assemble a set of classes that give us a modular way to represent a number of different kinds of buttons. Object-oriented design is paying off!

Now suppose that we want to use a few buttons as a set of filters. Something like this:

We need to be able to show active filters in some way. Let’s edit our original object definition to include a state class for a “selected” button:

.button {
  background: none;
  border-radius: 3em;
  border: 3px solid #67cef4;
  color: #67cef4;
  cursor: pointer;
  font-family: "Source Sans Pro", sans-serif;
  font-size: 100%;
  padding: 0.7em 1.5em;

  &.is-selected {
    color: #67cef4;
    background: #e8f7fd;
  }

  &:active {
    color: #67cef4;
    background: #e8f7fd;
  }
}

Here we’ve added an “is-selected” modifier class which we can use to show selected filters.

In Oxygen, state modifiers should almost always be bound directly to the object class name. In Sass we use the parent selector to achieve this, but you could do the same thing in pure CSS like this:

.button.is-selected {
  color: #67cef4;
  background: #e8f7fd;
}

This tight association between the object class name and modifier means that only objects with a class of “button” and “is-selected” will be affected by the above rule. This is essential so that other objects with an “is-selected” state are not modified by our button rule, too.

The “is-selected” modifier class is called a state modifier. As a general rule it’s helpful to prefix state modifiers with “is-”3 or “has-”. This will make them easy to recognize in your HTML and CSS.

Another rule for state modifiers is that they should almost always appear at the end of an object definition. This ensures that they will override any properties set in the original definition.

(One surprise here is that the :active pseudo class is actually a state modifier, too! Since there is a pseudo class for the active state of the button there is no reason to rap this up in an actual class just to observe the Oxygen best practice of using classes. The pseudo class will work just fine. Again, Oxygen naming conventions have a few exceptions.)

Attribute modifiers

A modifier class is the fourth kind of class in the Oxygen naming system. Above we used it to indicate state, but there is another type of modifier that is extremely useful when developing modular systems.

It’s called an attribute modifier. Attribute modifiers are useful to make one-off modifications to objects. Generally, attribute modifiers only change one or two attributes of an object.

Let’s look at a couple of examples.

Here are a couple of modifiers that I use to float an object left or right:

.float-left  { float: left  !important; }
.float-right { float: right !important; }

Another set of modifiers that I use are devoted to typography. Here are a few for adjusting font-weight on the fly:

.text-light     { font-weight: 100 !important; }
.text-thin      { font-weight: 200 !important; }
.text-normal    { font-weight: 400 !important; }
.text-semibold  { font-weight: 600 !important; }
.text-bold      { font-weight: 700 !important; }
.text-ultrabold { font-weight: 900 !important; }

And here’s a longer attribute modifier that is used to wrap up the concept that this object should only be “visible” to screen readers. Technically it breaks the convention of only modifying one or two attributes, but practically it is modifying the concept of “visible to screen readers” which is an “attribute” of the object:

.screen-reader-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0,0,0,0);
  border: 0;
}

Unlike state modifiers, attribute modifiers aren’t necessarily bound closely to a single object definition (all though they can be). Many of them will have global ramifications on all objects. Since they generally only modify an attribute or two, it’s useful (and not too dangerous) to use !important to ensure that they will always have the indented effect.

Parts of speech

So far we’ve discussed four different basic kinds of classes that make up the core of the Oxygen naming system. For the more grammatical among us it may be helpful to think about these conventions in terms of parts of speech:

Type Examples Convention
Object .button .menu .noun
Child-object .button-caret
.menu-item
.noun-noun
Subclass .primary-button
.popup-menu
.adjective-noun
Modifier .is-selected
.scrollable
.no-border
.prefix-adjective
.adjective
.descriptive-phrase

In case you need a bit of a refresher, a noun is a person, place, or thing, and an adjective is a word that describes a noun.

As you can see objects are almost always nouns. Subclasses generally combine an adjective with a noun. And modifiers are just adjectives or descriptive phrases.4

The importance of these noun/adjective naming conventions cannot be underscored enough. Learning to think in terms of nouns will help you identify the boundaries between objects in your system.

Word separators and capitalization

Oddly, word separators and capitalization are the least important part of the Oxygen system, but it is important to choose a method and be consistent about it’s implementation.

By default the Oxygen recommendation is to keep everything lowercase and separate words with dashes. This leads to class names that look like this:

.button             /* Object */
.button-caret       /* Child-object */
.primary-button     /* Subclass */
.is-selected        /* Modifier */

If you are able to keep the parts of speech distinctions in your head this is a fairly lightweight way to observe the conventions. It’s also a very traditional way of writing class names in CSS.

Some people may prefer more of a BEM-like approach to make the differences between parent and child objects more clear:

.button             /* Object */
.button__caret      /* Child-object */
.primary-button     /* Subclass */
.is-selected        /* Modifier */

Others may prefer to use capitalization to make objects and modifiers more distinct:

.Button             /* Object */
.Button--Caret      /* Child-object */
.PrimaryButton      /* Subclass */
.is-selected        /* Modifier */

It’s really up to you and your team to determine the best way to apply the conventions. The important thing is to be consistent.

Abbreviations

One final thing about naming conventions. To make naming easy I recommend that you almost never abbreviate class names. At first glance it may be tempting to abbreviate names to cut down on the number of characters you need to type:

.btn       /* Button */
.btngrp    /* Button Group */

While this is tempting, in practice saving a couple of characters in this way can make it harder to remember the names in your system. Was it abbreviated “btn” or “bttn”? How much easier just to spell things out:

.button          /* Button */
.button-group    /* Button Group */

If you are consistent about this you will find that it reduces the cognitive overhead needed to mark up your HTML. You’ll also find it easier to type.

There are legitimate uses for abbreviations. We’ll cover some of those in coming chapters, but for now keep it simple and you’ll stay on the happy path.

In summary

In this chapter we’ve done a quick fly-over of the four major parts of the Oxygen system and their naming conventions. We will look at other examples in future chapters, but this should give you enough to begin to apply Oxygen in your work.

This is a good chapter to recommend to others if they are looking for a good explanation of what Oxygen is and how it should be applied. Naming conventions when used consistently can make your code much easier to read and will enable teams to work together on the same code base.


  1. I will be using Sass in examples from here on out because it makes it easier to group rules into a single object definition. You can of course, accomplish the same things in pure CSS or using a different preprocessor like Less or Stylus.

  2. New to Sass’s parent selector? Read the article Referencing parent selectors using the ampersand character on The Sass Way.

  3. Giving credit where it’s due: I first learned of this convention in Jonathan Snook’s book, SMACSS: Scalable and Modular Architecture for CSS. See his excellent discussion of “State Rules” here.

  4. Technically modifiers can also contain adverbs and linking verbs (among other things), but let’s keep it simple. The key thing is that modifiers are descriptive.

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

Discussion