Truly scalable styles

Styles architecture are one of the most tricky aspects of building complex application for scaling. I think that comes from a conjunction of different factors the major ones being:

  • Beginner-friendly: upon a try/error approach you can get anything done in a couple of hours. If after that you'll be able to read it is another story. CSS can be harder to read than compiled Perl. (ok, maybe not, but feels like that sometimes).
  • There's no defined structure on how you should write your code. CSS is like that passive-aggressive person that makes all concessions and never complains while secretly is about to burst. You can basically override anything at any given moment of the code and get what you need done, if you're not on the look-out one day those side-effects come to bite you on your behind, but that's not your present self business, right?

There are of course other specifics that you can think of. But while any other inconsistent, feature-lacking, buggy nuance is being, quickly or not, addressed (and it is, take a look on how we used to write code not a few years back and you'll probably agree) these two aspects are what makes CSS so awesome.

Code degradation over time

Being beginner-friendly and having no concise structure make a dangerous combination to any language. You build your code, you ship it. We all know that's how ☠️ legacy code ☠️ is born.

Once the code is out there it's extremely hard to face the Technical Debt and refactor it. So, if you need to update/change/rebuild something, you end up doing it punctually. As time goes by product grows, your team grows and suddenly it's not feasible to understand where to change and how to maintain it, you may find yourself playing some short blanket.

Short blanket is when you pull the sheets up to cover your head and your toes slip out, then the other way around.

In software developing it happens when, by working-around a bug, you create another one to which you also work-around. Fortunately, there is a metric that have shown to ease code maintenance and decrease the degradation of your code over time.

Specificity Graph

What make selectors strong or weak is their specificity, for example

.btn {
/* props 1 */
}
.btn.active {
/* props 2 /*
}

Whenever there's a concurrency among them, Props2 will override Props1. The main reason is the selector for Props2.btn.active) is more specific than the selector for Props1 (.btn ). It actually speaks louder than the Cascading nature of CSS — which basically states that whatever comes later is preponderant to what comes before.

So, to the graph now!

Specificity Graph is an analysis made on your whole stylesheet and drawn upon a Cartesian Plane. The y-axis being the specificity of each selector while the x-axis is its location on the stylesheet (top → bottom).

Check the following example:

Specificity x Place on Stylesheet
Your graph should behave on a continuous increasing line with the least spikes as possible.

Spikes ratio x Maintainability

Having spikes allocated according to design as we normally do makes our code unpredictable, therefore unreliable. Thinking from other languages, you usually have pieces of your code where you can expect values to be returned, endpoints, etc. Basically you can predict where each module will affect the next one, that makes your code more maintainable: worst case scenario, you can refactor it all keeping consistent with the expected output (please, if so make a proper refactor later 😉).

If you're able to know beforehand the location of your styles major outputs at least, you may be able to stop being afraid of !important .

ITCSS

In play comes the Inverted Triangle CSS, the methodology originated with Harry Roberts, it's a bit tricky to find resources over the methodology, but I promise to leave on the References what I have (and please, if you've written or know more, feel free to add in the comments).

In this article, I'll explain basically about how I'm using it with some minor adaptations I've managed for my current workflow.

The Paradigm

As I said before, we've been writing CSS wrong because we've been trying to replicate page structure in our code, this doesn't respect the cascading nature of CSS.

The idea behind ITCSS is to organise your styles in a flow that respects their strength, and aims to decrease specificity spikes. In other words, say goodbye to header.css, footer.css , sidebar.css ,etc.

Inverted Triangle

The idea behind this concept is to follow from low specificity to high specificity. This modification of ITCSS that I prefer to use works with 5 layers of styles, with a possible 6th ramification (more on that later). If you're working on a small to medium application, these layers may be the modules themselves, but in bigger applications you can treat them as levels, categories, groups or layers of styles.

the layers of ITCSS
  • settings

If you use a preprocessor of any kind, first goes your variables and other basic/global configurations. Nothing gets straight to the DOM from here.

  • tools

mixins, functions and placeholders (no classes, never extend classes!). Still, keep it out of the DOM.

  • base

Finally you’re ready to start writing something that will effectively affect your mark-up: resets and/or basic definitions. And by basic, I mean basic. Here you give the look and feel of your default elements, it's the place where you can/should use Type Selectors.

  • components

At this point, you start with specifics. If your working with Atomic Design, for example, here you'd start with your Molecules and Organisms.

As I said, you can have a 6th layer. If your application is big enough, I'd recommend having a general layer before your components layer, there you can have the common styles for different components.

Here you should be using Classes and maybe some Descendant Selectors (not too much, if you go to up to 3 levels or more, you might want to re-think your approach).

  • overrides

And, as the name says ( trumps in the original ITCSS), it's where you put everything that is supposed to override something else. For example, states. Your .btn[data-active=true]or .btn.active goes here, etc…

And, as I said, if you follow this structure, here is the place where you can stop being afraid of !important . As they will all linger at the end of your code, and very close to each other it will be easier to spot any bugs you create down the line by using it. (not the you should use it, I'm just pointing it out! 😜)


If you liked this article, recommend it to your network by clicking on the 💚. This also provides me with a much appreciated feedback, of course, if you feel like providing a more extended one, I'm all ears (or eyes!) on the comment/response section!