CSS Good practices

In the past CSS had such limitations and was so badly understood by most developers that using frameworks or libraries was seen as the only way to get things working. Bootstrap was the king of CSS frameworks and with it came a ton of code that was most often not used at all. The only usable alternative was probably Foundation or SASS libraries like Susy.

Fortunately today we have a lot of choice! We still have Bootstrap, but also lighter alternatives like Bulma or totally different propositions like the utility first Tailwind. Also tools like Purge CSS can help reduce the size of CSS bundles by removing the unused parts of CSS frameworks.

In reaction to fully equipped frameworks we've also seen class-less CSS frameworks rising in popularity for a few years and they come with the promise of a small file size that correctly styles a website with only the HTML elements. That indeed sounds like a smart idea as it forces the developer to use semantic HTML.

But if you have to extend this kind of framework with your own design and don't want to use classes, you're going to create more troublesome code that you think.

Enters specificity

Specificity is the means by which browsers decide which CSS property values are the most relevant to an element and, therefore, will be applied. Specificity is based on the matching rules which are composed of different sorts of CSS selectors.
— MDN, About specificity

So what are the more specific and less specific things you can meet in CSS? Here's a list from more to less specific:

  1. IDs
  2. Classes, attributes and pseudo classes
  3. Elements and pseudo elements

Knowing this, some practices can create a lot more specificity than others. Among them, these are the worst:

Specificity is why a lot of people hate CSS:

So as you can see, it's not just a technical thing but a good practice methodology to take specificity seriously.

Chain elements or use a class?

To come back to our no-class CSS topic, we find ourselves in front of a dilemma.

Let's say you want to add red to your links located in a list in the navigation of your website, using only HTML elements and no classes. It would look like this:

nav ul li a {
    color:red;
}

Since browsers read CSS from right to left, each time they meet a new element in this declaration, they have to re-compute the design. This is how the browser interprets this chain:

  1. I style links to red
  2. Wait it's only links in lists that need red
  3. Crap, it was only links in lists in the navigation that need red

Unless you have a terribly big CSS file that takes a lot of time to be parsed and triggers a lot of refresh, of course you will not see this happening. But this is still happening under the hood.

Now let's compare this to a simple utility class:

.redcolor {
    color:red;
}By default text is black and background is white
<a class="redcolor">

With this code, the browser only thinks if I see a redcolor class, I add red. And that's it, no repaint, no problem. But here's the thing: chaining HTML elements is calculated as less specific than using a class.

So who is right and who is wrong? The browser is right, but ultimately, the no-class CSS is worse:

So in the end, using class is a better idea. The no-class CSS methodology is good, but only works as a starter point for global elements.

Tips and tricks for your CSS

So in the end what should you do if you want to maintain small CSS file size and low specificity? Here are some rules that you can apply to almost every project:

You can check your specificity using this specificity calculator and check if your file has his specific code in order (from less to more) using this specificity graph generator.

By doing this your code will be lighter, easier to maintain, reusable and extendable like objects, and won't trigger repaints.


Initially published: November 23rd, 2020
Generated: March 13th, 2022