My CSS methodology

How I write CSS: A step towards formalising my approach.

7 minute read

First up, an admission: I've never (fully) adopted a CSS methodology. In recent years, it has felt like any self respecting front-end dev should pick a side and embrace one of the popular approaches, whether that be BEM, SMACSS, Atomic CSS.. (the list goes on). Of course it's not really about picking a side, a lot of these approaches overlap or compliment each other. That being said, I think there are a couple of overarching ideologies at play, which, depending on to which you subscribe, rule in or rule out particular methodologies. These can be boiled down to CSS determined by HTML, and HTML determined by CSS. The former is a slightly abstract expression of the idea that content lives in HTML; and you style the content in CSS. The counterpart describes the newer idea of creating "utility classes" in CSS then adding them to your HTML (to style your content) as required. I mention this just to set out my stall, my default position is a strong preference towards CSS determined by HTML. I could make practical arguments for this (and I will in my next post), but in truth, people find success with approaches from both schools of thought. Some people love Bootstrap; Zen Garden still has a special place in my heart.

The methodologies most compatible with my ideals still contained enough undesirable stuff to put me off fully embracing them. I did however recognise a goal common to all of them - scalable, maintainable CSS. Over time I adopted elements from various methodologies, in particular:

  • A class naming convention
  • Limited cascades
  • A single code block per selector

I've found this approach of adopting solutions, as and when a benefit became tangible much more appealing than a wholesale adoption of something that didn't feel quite right for me. I can however, see a real benefit in using an established methodology (and I'm not ruling out ever doing so), in that other people working on the code know what to expect, and what is expected of them. For this reason I want to start the process of formalising and documenting my current approach to CSS. Here's my first pass.

The three 'C's #

My approach revolves around what I call the three 'C's - Component, Child, and Context. Let's call it C3. For those familiar with BEM, it's worth making an immediate comparison here, as I have borrowed a lot. In terms of definitions, Component and Child map directly to Block (B) and Element (E) of BEM.

Component #

A stand-alone, possibly reusable part of a page. Represented by a class. Class is named after what the component is (for), never what it looks like, or its state. Class names are formed of lowercase words, separated by a hyphen (-), though the only crucial rule is that underscores (_) are not permitted. Components can be nested within one another (in the markup, not in CSS).

Example #

html
<!-- valid component class -->
<nav class="menu"></nav>
<!-- invalid, we don't describe appearance here -->
<nav class="horizontal-menu"></nav>

Child #

Could more accurately be described as a Component Child, a Child is a constituent part of a Component, not intended to be used separately from it. Just like Components, Children are represented by a class, named after their purpose, and never their appearance or state. Class names are formed of the parent Component name, an underscore, and Child name (lowercase words, separated by a hyphen). Children can also be nested within one another (in the markup, not in CSS).

Example #

html
<ul class="menu"> <!-- Component -->
<li class="menu_item"> <!-- Child -->
<a class="menu_link"></a> <!-- Child -->
</li>
</ul>

Context #

Describes the context of a Component or Child. Context is represented by attribute selectors and/or media queries. Context describes circumstances, not appearance. In terms of media queries, this will be information about the viewport; attributes are used for things like state, role, or any arbitrary variable. WAI-ARIA should be used where appropriate, otherwise data attributes are used. Cascading is permitted here.

Example #

html
<ul class="menu">
<li class="menu_item">
<a class="menu_link" aria-current="page"></a>
</li>
<li class="menu_item">
<a class="menu_link"></a>
</li>
</ul>

Context is where my method most differs from others (that I've seen), so worth giving some comparative examples. When it comes to states, C3CSS is not far removed from BEM. The selector for the above active menu link would be: .menu_link[aria-current]. While in BEM it might be .menu__link--active.

The significant difference is that Context does not describe appearance, so things like colour and size require a different way of thinking. Take for example this BEM button:

html
<a class="button button--green button--large">

We have a button class, and we want a green variation of it, and a large variation of it. The C3CSS approach here is to ask "Why?". Perhaps the button is green because this is a positive action, in which case, our selector might be:

css
.button[data-type="positive"] {}

Maybe the button is large because its inside a banner/hero. In which case we might use:

css
[data-role="hero"] .button {}

It's worth mentioning tooling here. In practice I would be using PostCSS and writing the above examples like so:

css
.button {
/* styles */
&[data-type="positive"] {
/* styles */
}
@nest [data-role="hero"] & {
/* styles */
}
}

Note: Everything about .button can be found in this code block.

Why attributes over classes? #

This is just a style choice, chosen for consistency with ARIA, and to make it easy to identify each of the three 'C's: component, _child, [context].

Don't you repeat a lot of code? #

Yes and no. In terms of the code I'm writing, no; I make use of variables and occasional mixins to ensure consistency. There is potential for some repetition in outputted code; this is a conscious compromise. There are essentially two reasons why I am willing to make it:

  1. Rewriting templates to make stylistic changes is an unnecessary abstraction.
  2. Describing appearance in HTML is fundamentally at odds with responsiveness.

Start a conversation. @ me on Mastodon.