Sometimes writing CSS can be a tedious task even for those who are experienced. It's even worse for those who are new to web development. For the past few years doing web development for various clients, I have noticed that the usual pitfalls of writing CSS fell into one of these:

  1. CSS was written in such a specific way (sometimes too specific).
  2. Inconsistencies in how devs write CSS classes. The default standard for most CSS should be written in kebab-case. But I have seen a mixture of kebab-case, camelCase, and also TitledCase in a single project.
  3. Blindly implementing the whole Bootstrap framework as well as trying to keep own branding. I have seen teams import bootstrap.min.css then try hard overriding those stylings that they don't like.

So, here are a few tips that can reduce the pain of writing CSS:

1. Be consistent

Most front-end developers type CSS in all lower-case with - (hyphen) as the separator between words (e.g.: .table-heading). But, if your team has already done a camel-case or titled-case, make sure everything stays consistent.

2. Make reusable classes

The idea of writing CSS is to make them as reusable as possible to reduce the need for repeating the same code.
Avoid writing CSS like:

div#card {
    background-color: #eee;
    color: #000;
    text-align: center;
}

Write it in a more reusable way:

.card {
    background-color: #eee;
    color: #000;
    text-align: center;
}

You can further normalise the CSS for further reusability:

.bg-grey {
    background-color: #eee;
}

.color-black {
    color: #000;
}

.text-center {
    text-align: center;
}

You never know when you are going to reuse it. Making it specific to a particular ID is a bad practice because HTML can only have one element that has the same ID. Coupling CSS to ID makes it not reusable. Only target it to a specific ID if you are sure that you are only going to use that specific CSS styling to that specific element.
Do notice that if you are using Bootstrap, some of the CSS utility classes are available out-of-the-box.

3. Use CSS pre-processor

There are various CSS pre-processors available out there.

  1. Sass
  2. LESS
  3. Stylus
  4. PostCSS

For a small project, it might not be required. But when you are working on an enterprise-level project, styling consistencies are very important. CSS pre-processors help to keep your CSS DRY (Don't Repeat Yourself) by allowing you to keep commonly used things (like colours and stylings) in one place and make them reusable. Here are how we can leverage the benefits of CSS pre-processors:

  1. Use variables. Variables allow you to reuse certain value like margin or colour throughout your application. Example in Sass (SCSS):
$blue: #00f;
$default_margin: 1rem;

.bg-blue {
    // Background color will be *#00f* once processed
    background-color: $blue; 
}

.container {
    margin: 0 $default_margin;
}
  1. Use Mixins for some reusable set of styles. Example in LESS:
.rounded-border {
    border: 1px solid;
    border-radius: 4px;
}

// To produce CSS for black border with rounded corner
.black-rounded-border {
    border-color: #000;
    .rounder-border();
}

// To produce CSS for blue border with rounded corner
.blue-rounded-border {
    border-color: #00f;
    .rounded-border();
}

  1. You can easily change the base variable for some UI framework like Bootstrap and Material. Changing the base variable prevents the need to override CSS to suit your branding, e.g., font size, padding, margin, and also default colours. You need to make sure that you import the pre-processed CSS file (e.g.: .scss), not the compiled .css file.

4. Avoid !important !

Using !important can make your life hard. By default, any CSS property with !important takes precedence over any other CSS styling that is put into that particular component. It looks fine until you need to override that style that has !important. You will have to write a more specific CSS rule just so you can override it with another !important.

Instead, write CSS in either:

  1. Use specificity as much as possible. Rather than relying on !important tag, use any available parent's component or classes of the element to be the additional hook. e.g.:
.form-control {
    border: 1px solid grey;
    border-radius: 0.5rem;
}

.squared.form-control {
    border-radius: 0;
}

.seamless .form-control {
    border: 0;
}

Don't fall into this rabbit hole of !important like the example below:

.form-control {
    border: 1px solid black!important;
}
input.form-control {
    border: 1px solid blue!important;
}
.parent-class input.form-control {
    border: 1px dotted green!important;
}
#main-content .parent-class input.form-control {
    border: 1px dashed #eee!important;
}

  1. If by any chance you are using some JavaScript framework like React, Vue, or Angular; you can use a scoped CSS. Scoped CSS allows us to create a CSS specific to a particular component. It can be achieved by using some attributes appended to HTML elements. See the example below:
    13459_CSS%20specificity
    By having a scoped CSS, you have less specificity to worry about, since you don't necessarily need to override a CSS styling that is targeted for another component. All you need is to override base styling if required.

These are a few things that I've used in projects to improve the quality of our CSS. Sometimes you might think that using a pre-processor like SCSS seems overkill for your project. But, the benefit of simplicity and consistency outweigh the learning curve and setup time. I hope you've learned something from these tips. Have you got any CSS tips that I've missed? Please do let me know in the comment section below.

P.S: If you are ready to see the rabbit hole, CSS Cascade is a great resource about how CSS style 'cascade'.

Cheers!