I’m here to remind you that a naming convention for your CSS, even in 2022, with Cascade Layers, Web Components and more, might still be the most pragmatic and sensible choice for architect-ting your CSS codebase.
The last time I was on the ShopTalk show podcast, I talked about what I feel is the fundamental mental model to understand if you want to scale CSS across large codebases.
Abstraction v Isolation
I’ll try and surmise. Imagine a continuum, with complete isolation (ECSS/BEM/CSS Modules etc) on one end, and complete abstraction (championed and established by ACSS, iterated upon by Tachyons/Tailwind and others) on the other.
My conviction remains that being at either end of that continuum is the best way to author a CSS codebase that scales well. The venerable Chris Coyier summed up what I am getting at here.
Now, throw a rock in any direction and you’ll hit ten CSS methodologies. If yours is one, don’t be offended. I include my own ECSS methodology in that statement.
As far as I am concerned, each and every CSS methodology sits somewhere on that continuum. The approaches I personally favour, sit at either end. They are simpler.
Why I prefer the poles
With ECSS I apply a class to something and it gives me context, the component and the relationship of that element to the component. Its uniqueness isolates it and in turn makes it easy to delete. On first exposure, the naming convention might seem like a lot of work for a humble selector but that is pretty much all you need to think about.
Abstraction is equally compelling in the opposite direction. It provides no opinion other than what is does. That approach is not my preference but I appreciate it’s validity, and plenty of others (waves hand in direction of most other devs) prefer that approach.
Anything else is in the middle of our continuum, and so communicating things like context or applicability (utility etc.) is done in one of a few ways. Concepts like layers of styles are common. Some use particular selector naming conventions, some use the file name they live in.
If the extremes of isolation or abstraction don’t suit you, there will be something in this middle ground that does. This post isn’t to debate the merits of each, whichever you choose, if it works for you, more power to ya!
Modern additions to the language help out in this middle ground. Browser support is an issue right now, but before you know it, you will be able to reasonably use Cascade Layers in a project. The reason it’s not something I would recommend right now, it that it is not easily ‘polyfillable’. However, even if support were ubiquitous, despite use cases like controlling third party code, which it excels at, I’m not sure I would use it to organise my CSS anyway. It’s just not how I think about my code, and fundamentally addresses problems that, thanks to a CSS class-naming convention, I don’t have.
So, we’ve established that I am firmly in the isolation camp. Surely something like Web Components, where you get genuine, built-in CSS isolation, means a CSS naming convention is unneeded? That’s what I hoped. But after a couple of years with Web Components, I don’t think that’s the case.
There are two problems I’d like to talk about with CSS and Web Components. Firstly, elements don’t have no opinion. They have the same opinion a browser has on any element. And it is the same for every component you create.
They start with the same defaults you almost certainly never want, especially if it is an application you are building. You get the default margin on
h1,h2 etc same Arial font on buttons etc. So every component tends to need some sort of reset. The inherent isolation of a web component is a double-edged sword. Sure, styles outside can’t get in or out, but you also can’t get anything global in either.
Now, as each component needs a reset, you can imagine that might lead to a lot of bloat. Thankfully there is light at the end of that tunnel. Chrome and Firefox have implemented constructableStylesheets to solve this issue. The only downside is that WebKit/Safari hasn’t yet. Things like Lit, which is my preferred way to work with Web Components, handle this problem for you but it is something to be aware of.
The second issue is one of comprehension. Most of the stuff I work on is application-y stuff – not documents. Every node in a component tends to be doing something different. So you quickly run out of HTML elements with which to use if you have abandoned class names. After you have worked your way through
i things get tricky. And anywho, doing that is actually worse as you are adding different html elements, purely as styling hooks, elements that may intrinsically have little bearing on what you are actually using them for. So, no, no and thrice no.
Now, you can of course go all in, and make everything a component in its own right. Instead of
.ac-Settings_Header, you might opt for
account-settings-header. But, while that works, it doesn’t get you anything you didn’t already have with a class.
It can also be useful to have an existing HTML element as the basis for your thing. Something like a
dialog, is doing so much for you ‘for free’, it would be futile to want to remake them. So if you do go with just web components as styling hooks, you will inevitably get to a point where you need an extra hook on an element, just for styling. So now you have two types of styling hooks in play, the new element, and a class to control it in different situations. When just using a class you only ever needed one. A CSS class naming convention wins out.
Faster and easier prototyping and on-boarding
With a CSS class naming convention, you can prototype easily; stub a component out with raw, and more semantically appropriate HTML and CSS, and then move that into something like a Web Component as needed. It’s ‘production useful’ code from the outset.
Every editor/IDE you open understands CSS and HTML. This maybe only a tangential consideration but I have found that bringing new developers into the fold is easier because they can be contributing from the outset.
I’m not here to say using a CSS naming convention is the only way. But rather to implore you to weigh this stuff up.
At work we have made decisions and technical choices that the Web Dev/Rel ‘illuminati’ would frown upon. But they were the right choices for us. For our product, for our developers.
So when it comes to architect-ting your CSS codebase, you’ll probably want/need to try a few approaches. Live with them a while. Analyse the merits and shortcomings.
Plenty of people go the full abstraction route, championed back in the day by Thierry Koblentz and the Yahoo team as ACSS, and now
stolen claimed by countless others and popularised with Tailwind.
Others still use CSS modules. That does the same thing that a naming convention does and does it automatically. Only trade off there is the need for tooling.
Yet other people opt for something else entirely.
For this developer, I’m sticking with a manual CSS naming convention. In the last 10 years tooling has come and gone, frameworks and libraries have been sun-setted, and brand new possibilities like Cascade Layers have been made possible on the Web Platform. But the usefulness and resilience I have enjoyed from a good CSS naming convention has not diminished.
Maybe something like ECSS might be the right thing for you too?