October 31, 2013

Escape Your Way to More Meaningful Class Names

As part of a recent movement to think critically about our front-end best practices, many of us are reconsidering the merits of presentational class names (things like span-3 or inline-list), previously frowned upon as “unsemantic”1, 2. Building on these ideas, I’ll show how character escapes, a little-known feature of CSS, can help make these presentational classes both more versatile and more readable.

I’ll assume you don’t categorically disagree with the concept of presentational – or “utility” – classes (for more on the topic, Philip Walton’s exploration of the topic is instructive). In practice, two of the most obvious places we can put them to work are spacing and grids.

Spacing

Thinking in systems is useful, so I like to use a couple of basic units to help guide the proportions of a design. Often, this will be the basic font-size and leading (line-height). When building out the site, I use Sass to define variables for these, and I have a baselines() function that provides multiples of my basic line-height. I then use this function to define a set of utility classes for expressing vertical spacing. I find that inter-element spacing is better handled locally than by giving this responsibility to each component, because the spacing is often contextual. By using a relative unit – and one that relates to the design – we can still avoid encoding rigid values into markup:

.leader-h           { margin-top:    baselines(0.5);  }
.trailer-h          { margin-bottom: baselines(0.5);  }
.leader-hq          { margin-top:    baselines(0.75); }
.trailer-hq         { margin-bottom: baselines(0.75); }
.leader, .leader-f  { margin-top:    baselines(1);    }
.trailer, trailer-f { margin-bottom: baselines(1);    }
.leader-fq          { margin-top:    baselines(1.25); }
.trailer-fq         { margin-bottom: baselines(1.25); }

Unfortunately, these the names are pretty inscrutable. If we’re going to use presentational class names, it’s best to make them clear to as many developers as possible. The biggest issues in this example are a) my use of letters to represent numbers – “h” for “half”, “q” for quarter and “f” for full – and b) the notion of combining them to express fractions. What would be instantly understandable as “3/4” or “0.75” gets written as “hq”. If I could just use slashes or periods in my selectors I’d have much clearer class names.

It turns out this is possible: “special” characters like slashes, periods and leading numbers can be used as long as they’re escaped with a leading backslash. This works (with a few exceptions like the colon character) in all browsers; (Mathias Bynens has the all the details. He’s even made a neat little tool.) So there’s at least one place where this feature stops being a curiosity and starts having practical value. Here’s an updated version of the previous spacing utility classes:

.leader-0\.5   { margin-top:    baselines(0.5);  }
.trailer-0\.5  { margin-bottom: baselines(0.5);  }
.leader-0\.75  { margin-top:    baselines(0.75); }
.trailer-0\.75 { margin-bottom: baselines(0.75); }
.leader-1      { margin-top:    baselines(1);    }
.trailer-1     { margin-bottom: baselines(1);    }
.leader-1\.25  { margin-top:    baselines(1.25); }
.trailer-1\.25 { margin-bottom: baselines(1.25); }

The downside is the readability of the stylesheet. The reason this might still be a net win lies in how we use utility classes. Because these classes do one thing well, they need to be written at most once per project. In other words, they function more like a library, and we implement them in markup. And in markup there’s no need for escaping:


 

Grids

Grid systems are probably the most familiar application of presentational classes. Here’s a simple grid for current browsers:

.grid {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  margin-left: -16px;
  margin-right: -16px;
}
.grid__span {
  float: left;
  padding: 0 16px;
}

.width-1\/3 {
  width: 33.333%;
}
.width-2\/3 {
  width: 66.666%;
}
.width-1\/2 {
  width: 50%;
}
.width-full {
  display: block;
  float: none;
  width: 100%;
}

The layout technique is beside the point (for those interested, it’s based on Zurb Foundation’s grid, but is ultimately closer to Nicholas Gallagher’s SUIT grid). The thing to note is the use of fractions in the class name. The implementation looks like this:


 

Going Responsive

The most obvious practical challenge for utility classes lies in responsive design: especially for a grid system. Much of the time, any given width class applies only at one breakpoint. If the aim is to maintain the classes-in-markup approach, the common solution is to apply additional classes that are scoped to media queries in the stylesheet.

Foundation’s implementation looks like this:


 

This works, but it could be clearer that the small-2 and large-4 classes apply column widths, and which of them express media-scoped styles.

Here’s a different take that uses an @ sign and a suffix to denote media-bound styles, providing better clarity about what’s going on:


 

And the additional SCSS:

@media (min-width: $medium-width) {
  .width-1\/4\@medium {
    width: 25%;
  }
  .width-3\/4\@medium {
    width: 75%;
  }
  .width-1\/3\@medium {
    width: 33.333%;
  }
  .width-2\/3\@medium {
    width: 66.666%;
  }
  .width-1\/2\@medium,
  .width-2\/4\@medium {
    width: 50%;
  }
  .width-full\@medium {
    display: block;
    float: none;
    width: 100%;
  }
}

Even for me, this is probably the upper limit for escaped characters in a single selector.

A final caveat: your workflow and web framework of choice make a difference. Some frameworks – including Drupal – make writing and changing markup harder than working with CSS. If you work with similar tools, you’d be justified in minimizing the use of utility classes in preference to CSS Zen Garden-style approaches. Still, even though I use these techniques less than I might otherwise, I’ve found them strategically useful on most projects.

If you’re at all interested in embracing presentational classes, it’s worth looking at any naming conventions you use for ways to be clearer about meaning and intent. Especially for utility classes that you’ll work with mostly in markup, a “special” character or two in your class names might be just the thing you need.