How I CSS

I’ve written a lot of CSS over the past six years. Here’s the opinionated result of all that experience. Maybe some day, after I’ve written even more CSS and changed my mind again, we’ll revisit this post and have a hearty laugh at how naive I was.


In this post:

Code style

For classes, I do lower-kebab-case. IDs get lower_snake_case. I’m not too terribly opinionated about comments, other than preferring to see them above the code they reference. If comment line gets too long, I have no problems wrapping it for readability.

// This class is necessary to prevent reactor meltdown.
.no-go-boom {
  // Use `fixed` instead of `sticky` so that it
  // always stays in place.
  position: fixed;
}

I tend to stick to the “one property: value; per line” rule, except for those properties that get pretty gnarly. For example, I use newlines for my gradient styles:

.background-gradient {
  background-image:
    linear-gradient(
      var(--g-background-gradient-direction),
      var(--c-gradient-color1),
      var(--c-gradient-color2)
    );
}

This helps keep line lengths in check and makes it a little easier (for me, anyway) to consume.

Beyond that, it’s all pretty standard stuff. I keep my selectors one-to-a-line, put semicolons on my final properties, and slap that closing brace on its own line because it deserves it.

Naming conventions

I stick with Harry Roberts’ namespaced BEM in most scenarios. I’m a big fan of BEM, and an even bigger fan of how these namespaces help keep me organized. It’s true: BEM class names can get loooooooong, but I’ve come to appreciate a few extra characters for the sake of clarity. We all might be able to understand .btn, but ain’t nobody getting to the bottom of .prim-crd-hd-top (pardon the hyperbolic example 😆).

Lately, however, I have started to pull back from enforcing BEM in full. Dabbling with component-based UI architecture has removed a lot of the need to be so explicit with my class names. Whereas I previously might have written something like…

.c-card { /* card container styles */ }

.c-card__header { /* card header styles */ }

.c-card__content { /* card content styles */ }

.c-card__footer { /* card footer styles */ }

I now opt for something like this:

.c-card { /* card container styles */ }

.c-card > header { /* card header styles */ }

.c-card > div { /* card content styles */ }

.c-card > footer { /* card footer styles */ }

I looked down upon the latter example as pure heresy for the longest time. However, my specific experience in my current role has led me to ease up a little bit on the BEM intensity.

For starters, I’m usually the only one looking at the CSS (and guiding the accompanying HTML development). So the only person that really gets any benefit out of seeing <header class="c-card__header"> vs just <header> is…me. And it turns out that I don’t actually care that much. Targeting bare elements within a parent CSS class has been working out just fine, and has actually reduced the number of HTML errors since transitioning away from full BEM.

I’ve also discovered that for refactoring, you almost always have to touch the HTML and CSS anyway. Going full BEM might be okay for something as simple as the .c-card example above, but some more complex components are not guaranteed to always have the same pieces with the same relationships when it’s time for an update. If I have to do at least some of it all over again, I may as well quit pretending and adopt a strategy that helps my developers write valid HTML.

I’m not trying to sway anyone’s opinion here. I still love BEM and don’t hate the time I spent going whole-hog. But after stepping back to look at the coordination of HTML and CSS and JS, and considering the experience my developers were having trying to work with what I was giving them—this compromise is working out much better so far.

Property order

I order my CSS properties alphabetically, with a twist: properties that depend on other properties are further alphabetized under the “parent” property. If the properties map to a part of a short-hand value (like background-attachment and background-position from background), I alphabetize those as well. If I’m using a mix of short-hand and explicit properties, I use the shorthand first, then alphabetize the remaining properties. When the properties reference a particular side, like border-left, those are organized in the same clock-wise fashion CSS uses—top, right, bottom, then left.

Clear as mud? For example:

.my-cool-demo-class {
  background-color: #c0ffee;
  color: #123456;
  position: absolute;
  top: 4rem;
  right: 1ch;
  bottom: 0;
  z-index: 9;
}

.another-one {
  border: .125em solid var(--c-body-background);
  border-bottom-width: .25em;
  border-left-color: var(--c-body-text);
  margin: 1em;
  margin-top: 0;
}

It’s janky, and not all that approachable for a newbie (or anyone at all?), but it really helps keep my mind straight. The methods for grouping styles based on their role (color, then layout, then position, etc) confuse the heck out of me. I can move a lot quicker by flipping through an alphabetized list (I know we’re all using search and goto here, just humor me). I should probably just get one of those plugins that automatically alphabetizes things on git commit 🤷‍♂️.

File organization

The namespaces make this pretty straightforward. Even if I’m writing pure CSS, like on this here blog, I still take advantage of SCSS when offered for at least its concatenation feature.

Every namespace gets a folder, and every folder is filled with SCSS partials that encapsulate some scope of styles. That could be a collection of small @functions, a grouping of loosely-related “global” styles, or a single component’s worth of CSS. Everything then gets rolled up into one big ol’ manifest that compiles it all down to the requisite .css file(s).

Compared to my hardcore property ordering approach, I try to stay pretty lax in this area. I let the needs of the project and the reality of the codebase drive its organization.