[nolan@nprescott.com] $>  cat blog archive feed

Simple, Unique CSS

2016-03-20

I am in the habit of using an esoteric system for CSS. This posts documents it so I have a reference in the future and so I look like less of a crazy person to anyone browsing my CSS.

It's Not My Fault

The idea isn't my own, a colleague introduced me to it several years ago, to my knowledge he's never bothered to write up his ideas. I realize there exist tools to accommodate these problems but heavy-handed tooling has never jived with me. I've tried to keep up with recent trends in the CSS ecosystem including BEM and SASS to identify the useful parts which I might incorporate into my current practices.

What Does It Look Like?

The big picture is simply "globally unique class-level selectors only". Which means rather than using top-level selectors like div and a or ID selectors like #app I use .btn-99f70 and .app-container-5283a. I realize how weird this looks.

How Is It Accomplished?

By using a random 5 character hex string on each class you guarantee uniqueness. The 5 character limit is enough to guard against collisions while still being memorable and largely unobtrusive (to my eye). The number of possible permutations for 5 characters of the hex range (16 characters) can be expressed as:

165 = 1,048,576

Meaning the chances are vanishingly small that you might name two buttons or links the same.

Why?

Using only class-level selectors results in levels of specificity which may be combined in a predictable manner. This is not a unique idea, it is present to some degree in:

I've been reading recently about how some companies "do CSS" and was interested to see that it isn't a solved problem for some of the big names. For instance, reading about GitHub's CSS:

The order in which styles get applied matters. It really shouldn't, but in every design system there are rules and a basic hierarchy of styling. With the Sprockets approach, we sometimes run into specificity problems. This happens because new files can be added to either bundle at any time. Depending on their file name, they appear in different spots in the compiled CSS.

Also, regarding how they manage stale classes:

Running a script that greps for a class in our CSS to see if it exists in our views. (We've recently made this part of our CI tests, so we constantly see it now.)

It so happens that with unique class level selectors this is a trivial operation and can be combined with diff to check a whole project. I use ag to do this, but grep or ack can accomplish the same:

  find-classes() {
      ag -oH --nocolor --noheading --nofilename
      '[A-Za-z0-9-]+\-(?=.*[0-9])(?=.*[a-f])[a-f0-9]{5}'
  }

I like to find those classes present in my CSS but not present in my views with a simple process substitution and diff:

diff <(find-classes css/*) <(find-classes views/*)

Further Reading

Another interesting read was CSS at Lonely Planet, the highlights for me were:

I sometimes want for variables with this system, which seems like a common theme and driving reason for the adoption of pre-processors. I think instead what I will aim for in the future is the use variable-like classes, in the vein of clrs.cc (.blue-998bc and .bottom-border-c61c9).

And most recently, Medium's CSS is Actually Pretty Fucking Good. The honesty of how far they had to come was refreshing and there were some interesting ideas here that I hadn't see before or that echoed my own sentiments.

That's Nice But...

This system matches my personal style of development and avoids the need for complicated tooling. It does lack some of the niceties other systems provide but I think that forces me to assess what I include in a project. It allows for quick audits on a CSS code-base and avoids the specificity conflicts present in some traditional systems. I'll continue to follow emerging trends, but for now I think I manage okay with simple, unique CSS.

[nolan@nprescott.com] $> █