Articles on "best practices" are opinionated, as they are based on the author’s specific experiences and goals—advice for working with large teams, for example, won’t necessarily speak to the challenges of making a website alone. There are certainly many ways to write "clean" CSS, but the opinion of this article is that in all circumstances the cleanest CSS always achieves these goals:

The best examples of code meeting these goals are subjective, but if we think of writing clean code as the ability to teach someone else, we can identify some objective criteria: clean CSS should be clear, organized, and straightforward. However, the question is, how can we teach someone how to understand our CSS? In my opinionated experience, the size of a codebase should direct our approach in organizing our own thoughts and in teaching others.

A Spike

Let's say you have an idea for how to execute a feature, but you're not quite sure of the best way to implement it yet. Do you use grid? Flexbox? Floats? Tables?? You need to experiment until you decide on a solution, knowing that your work will be destroyed when it's time to build it again "for real." This is the CSS for a proof of concept.

Goals

Process

In many ways, this is no different from puzzling your way through the first CSS tutorial of your career. If you are truly writing temporary code, then it is not important to think about teaching others on the first draft; thinking through the first draft is what allows you to teach others in the next iteration.

Example

.cat {
  background-color: red;
  /* display: none; */
  /* display: block; */
  display: inline-block;
}
.pizza-cat {
background: url('/images/pizza.jpg');
  background-size: 100px 100px;
  width: 100px;
  height: 100px;
  display: table;

  &:hover {
    color: white;
  }
}
.asdf {
  height: 100%;
  height: 100vh;
  min-height: 100px;
  flex: 1;
}
.asdffff {
  height: 100% !important;
  /* height: 300px; */
  min-height: 100px;
  flex: 0 0 100px;
  flex-direction: column;
}

Small Project with Fixed Scope

Perhaps a friend has hired you to make a website for their small business, or a relative needs a website to host their résumé. This category describes a project with only a handful of different pages which you will only ever touch once (hopefully). The requirements and scope of work fit neatly into the email that kicked off the project.

Goals

Process

However adamantly your client insists they won't request changes, don't discount the possibility of scope creep beyond what was originally promised. Software is complex because each project is unique; who can accurately predict the best final product when no one has ever made this exact website before? Regardless of your client's clarity of vision or strength of communication, expect to modify and revise your code.

For this type of project I prefer to use as few classes as possible. When each HTML element only appears in one context across all pages, why create classes? The purpose of HTML elements is universal, but your particular take on classnames is not. I like to style projects of this size as if I were writing rules for a brand's style guide to be applied universally to the entire project. While this approach yields a "clean" stylesheet composed mostly of plain HTML elements, the downside is that a website can only handle so much variety: introduce enough features and eventually you will need to introduce variations, which means adding classes for new components as well as refactoring selectors for plain HTML into classes.

Example

article {
  max-width: 750px;
  width: 90%;
}

h1 {
  font-size: 2.625rem;
  line-height: 3.975rem;
  letter-spacing: 1px;
}

p {
  margin-bottom: 1rem;
  }
  
a {
  color: $primary;
  text-decoration: none;

  &:hover {
    color: $primary-hover;
    cursor: pointer;
    text-decoration: underline;
  }
}

Medium Project with Increasing Scope

When starting a greenfield project, the Style Guide approach will carry you far, but eventually something will break if you haven't planned for expanding the original feature set. The solution here is to anticipate rules and architecture before you need it, allowing your project to grow beyond the limits of your imagination. Ideally, copying off of your past self is a great reference: re-use strategies that served you well on previous projects, and discard approaches that spiraled out of control. However, when such a reference isn't available, refactor early and refactor often. In fact, aim to refactor early and often regardless of how confident you are in your reference materials.

One aspect of planning for expansion is planning for adding new members to your team, or the possibility that one day you will no longer be working on the project. Writing clean CSS always depends on clarity, but note that clarity for your sake is different from clarity for the sake of someone you have yet to meet.

Goals

Process

I consider the most flexible style of CSS to be a combination of two approaches: the first approach is to scope vanilla HTML elements under a single containing class or element, like writing a self-contained style guide. This approach maintains the familiarity of regular HTML, only asking that the reader learn the classname of the context they are viewed in.

The second approach is to define a collection of universal classes that can easily be applied by any contributor to the project—designer OR developer. Given the heavily component-ized nature of Javascript apps these days, managing many states under one component class will cause many exceptions; why not make classes for the most common exceptions and save yourself the effort of duplication? Classes for margin, padding, position, and spacing are the most adjusted properties in any project; save time in readability, maintainability, and extendability by clearly labeling their use.

Example

.hgroup {
  display: flex;
  flex-direction: row;

  h1, h2, h3 {
    flex: 1;
  }

  button, a.button {
    font-size: 0.85rem;
  }

  span {
    color: $medium-grey;
  }
}

header {
  a {
    padding: 1rem 1.3125rem;

    &:hover {
      background-color: $light-grey;
      color: $primary;
    }
  }

  ul {
    display: flex;
  }

  li {
    margin-right: 1.3125rem;
  }

  li:first-child {
    flex: 1;
  }

  li.logo:hover {
    opacity: 0.5;
  }
}

.small-margin-bottom {
  margin-bottom: 0.625rem;
}

.margin-bottom {
  margin-bottom: 1rem;
}

.medium-margin-bottom {
  margin-bottom: 1.3125rem;
}

A Note on User-Generated Content

Some projects render HTML that you will never see, and—most importantly—that you will never be able to modify. As an example, this blog publishes markdown files written by multiple authors, who should not be expected to remember and apply classes throughout their articles. Aim to style components like this one with a single class on a container element as in the examples above, and collect vanilla HTML elements inside as if writing a style guide for a specific subsection of the project. This approach is a clear way to write any component, blog post or not, by scoping your changes to a single class.

Example

.blog-post {
  h1 {
    margin-bottom: 0.375rem;
  }

  h3 {
    margin: 1.3125rem 0 0.625rem;
  }

  p {
    margin-bottom: 1rem;
  }

  ul {
    margin-bottom: 1rem;
    position: relative;
  }

  li:before {
    content: '';
    background-color: $black;
    border-radius: 50%;
    display: block;
    position: absolute;
    top: 12px;
    left: -12px;
    width: 4px;
    height: 4px;
  }
}

Large Project that Never Ends

If you've been brought on to an enterprise project, give the existing code a thorough review before making any changes or adding any new features. If the person before you wrote easily readable, maintainable, and extendable styles, then congratulations! You have hit the jackpot. Just follow the architecture they laid out and stop reading here. However, if you can't make sense of their system—or worse, you can't tell if you'll break something by extending it—make sure your own microcosm of CSS is both easy to follow, extendable by other designers, utilizable by other developers, isn't going to break existing styles, and isn't going to break because of existing styles.

Goals

Process

Much of the existing literature on writing sustainable CSS assumes you are working with a team on a project of unknown size, which means the methodology presented needs to hold up at an enterprise scale. BEM is a popular system of categorizing each HTML element put on the page with a logical description of its purpose. By design, each BEM class is independent of all other classes, which eliminates cascading issues and avoids legacy code. This particular methodology is a fine, yet opinionated approach to writing clean CSS, but if its redundancy impedes too much on the elegance of your code, in my opinion you have my permission to get your team on board with a different approach, so long as it also meets the goals of this section.

Example

<button class="button"></button>

<button class="button button--state-success"></button>

<button class="button button--state-danger"></button>

If the best way to learn is to teach someone else, then the simple reframing of your perspective toward teaching future readers of your code will cause you to write CSS that is more readable, maintainable, and extendable than before. Regardless of whose opinion you value enough to listen to, the best CSS can be easily understood by someone you have never met, and hopefully the opinions contained within this article will help everyone who reads your code to understand it better.