CSS Architecture and the Three Pillars of Maintainable CSS

Share this article

CSS Architecture
CSS Architecture

Elements of CSS Architecture

If you have ever inherited bad CSS with the obligation of maintaining it, you might have felt some empathy towards others who would maintain your code in the future. In extreme cases, developers have no other choice, but to completely rewrite the CSS of an application. These extreme cases occur when each patch introduces multiple unwanted side-effects. Once you get to this point, your stylesheets become unmaintainable.

You can only avoid giving your future self a checkmate by making architecturally solid decisions now. This is why it is important to learn the ins and outs of building a maintainable CSS architecture in practice.

If you don’t want to be the person passing on bad code, you may wonder how you can create maintainable CSS from scratch. Where would you start? Let’s look at the elements of CSS architecture that are worth considering when it comes to building your perfect project.

Three Pillars of Maintainable CSS

There are three concepts worth considering when designing the CSS architecture of a software system. These concepts are so fundamental we can consider them like pillars holding up the structure of a building. We need all three pillars to make our CSS endure the test of time and doesn’t collapse into an unmaintainable mess.

The first pillar defines the building blocks of your CSS architecture. These building blocks consist of a wide variety of solutions and tools, such as using Sass, writing efficient CSS selectors, the block-element-modifier (BEM) syntax, using classes instead of ID attributes, and using relative units where appropriate.

Although this perspective gives you measurable improvements in your CSS code quality, we need a higher level of organization to make our efforts systematic. Therefore, we need a second pillar that focuses on the orchestration of building blocks to establish solid, maintainable, hierarchical CSS. Think of this layer as the skeleton of your CSS architecture. If you are interested in two ready-made CSS architectures, research a bit more about ITCSS and SMACSS.

Unfortunately, neither the building blocks, nor a methodical usage of a framework or a CSS architecture give you the answer to writing rock solid, maintainable CSS. Our code becomes solid through the application of software engineering principles. This is the third pillar of writing maintainable CSS.

Applying Software Engineering Principles to CSS

There are many different principles for engineering software that lasts.

These principles are responsible for providing a purpose for using the CSS tools and solutions of your choice, through making sure that your CSS code models reality in a maintainable way. Without these principles, using any CSS architecture is mostly a ritual. Writing CSS without respecting software engineering principles tends to collapse under its weight once the size of the code becomes unmaintainable.

If you are a software engineer experienced in some programming languages, you may find the application of these principles to a declarative language like CSS quite surprising. In practice though, CSS has become a mature language, and similarly to other languages, structure is a thoughtful consideration of the code needed. Let us examine some of the main principles in action.

Separation of Concerns

Separation of concerns is a software design principle responsible for defining clearly separated responsibilities in a software solution. The most obvious application to CSS is the separation between classes used for styling and classes used for functionality. Styling classes should not end up in JavaScript code, and functionality related classes should not end up in your stylesheets.

SOLID Principles

Robert C. Martin defined five SOLID principles. Some of these principles apply to CSS just as well as to other programming languages.

In my course on CSS Architectures, you will find many different applications detailing how to use these SOLID principles including the Single Responsibility Principle and the Open-Closed Principle in the context of CSS code.

When it comes to stylesheet hierarchies, we apply the Single Responsibility Principle. For instance, a layer in the ITCSS architecture contains resets or normalizers. Tag styles are built on normalizers, and component styles are built on tag styles. Each layer has one single, clearly defined responsibility.

Possibly the best known example for applying software engineering principles to CSS code is the contrast between DRY and WET CSS. The acronym DRY stands for Don’t Repeat Yourself, while WET stands for We Enjoy Typing.

DRYing out your code leads to better maintainability, because whenever you make a change to DRY code, you can perform that change in just one place with a high degree of certainty that you don’t have to research the rest of your CSS code-base for other occurrences of the same code.

When your CSS is WET, you can DRY it out by identifying the common pieces of your code, and abstracting this common functionality into a base class (or a mixin if using a pre-processor).

Using base classes and child classes in your code is called inheritance, and it is performed with @extend in Sass. When we use mixins, or the @mixin directive using Sass terms, we use composition. Inheritance, composition, and the usage of Sass constants are great tools for performing abstraction.

Experimenting with Composition in CSS

Let’s take a look at a practical example. Suppose we have four types of rectangles in our codebase. A generic one, a rounded rectangle, a green rectangle, and a rounded green rectangle.

We might mark up each rectangle component as follows using the BEM naming convention:

<div class="rectangle"></div>
<div class="rectangle--rounded"></div>
<div class="rectangle--green"></div>
<div class="rectangle--rounded--green"></div>

Let’s define these four classes in Sass using inheritance. We start with the base class of .rectangle and then create modifier classes which inherit styles from the base class using Sass @extend:

.rectangle {    
  width: 200px;  
  height: 100px;  
  margin: 20px;  
  padding: 20px;  
  display: inline-block;  
  border: 1px solid black;
}
.rectangle--rounded {  
  @extend .rectangle;
  border-radius: 20px;
}

.rectangle--green {  
@extend .rectangle; 
  background-color: green;
}

.rectangle--rounded--green {  
  @extend .rectangle--rounded;  
  @extend .rectangle--green;
}

The structure is clear, and we do not repeat ourselves in the modified classes. However, creating a hierarchy of five modifiers would yield in 31 class definitions, where most of our definitions would contain nothing more than a collection of @extend directives.

Composition gives us a more robust structure. In order to create a fully flexible structure, all we need is the generic rectangle class, and two mixins:

@mixin rounded {  
  border-radius: 20px;  
}

@mixin green { 
  background-color: green;
}
Suppose we have a special feature box.
<div class="feature-box"></div>

If the feature box is rounded, but not green, all we need to do is extend the rectangle class, and include the mixin that makes the rectangle rounded:

.my-rectangle {  
  @extend .rectangle;  
  @include rounded;  
}

The structure stays flexible, without the overhead for defining classes for each combination.

Towards a Better CSS Architecture

We can conclude that software engineering principles apply to CSS as to any other programming language. These principles lie between two levels: the micro level of CSS building blocks, and the macro level structuring of these building blocks. As a consequence, it is beneficial to learn how to apply these principles in practice, when it comes to creating maintainable CSS.

To help explain and demonstrate practical application of each of these principles, I have created a course on rock solid CSS architecture; Principles of CSS Architecture

In this course, we explore all three pillars of CSS architecture, putting a lot of emphasis on software engineering principles. You will not only learn these principles in theory, but you will also get a chance to use them in many practical examples.

CSS Architecture image

For instance, we will take a bunch of blog posts, and identify why the supplied CSS code is unmaintainable. We walk through the process of refactoring the CSS step by step, applying the principles briefly presented in this article and covered in depth within the course videos.

I’ve dedicated a complete section on putting the three pillars of CSS architecture into practice by creating a small component library using the ITCSS architecture and Sass. If you are interested in learning more about CSS architectures, sign up for the course, and see you inside!

Principles of CSS Architecture

Frequently Asked Questions on CSS Architecture and Maintainable CSS

What is the importance of CSS architecture in web development?

CSS architecture plays a crucial role in web development. It provides a structured way of writing CSS code, making it easier to understand, maintain, and scale. With a well-defined CSS architecture, developers can avoid issues like specificity wars, naming collisions, and code duplication. It also promotes code reuse, reducing the time and effort required to build web pages.

How does the OOCSS methodology contribute to maintainable CSS?

Object-Oriented CSS (OOCSS) is a methodology that promotes code reuse and faster, more efficient stylesheets. It encourages developers to see CSS as a system of objects, each with its own properties and behaviors. By separating structure from skin and container from content, OOCSS makes it easier to create scalable and maintainable CSS.

What is the role of the BEM methodology in CSS architecture?

Block, Element, Modifier (BEM) is a naming convention for classes in HTML and CSS. It provides a clear, strict structure that makes the code easier to read and understand. BEM methodology helps in creating a robust and scalable CSS architecture by reducing the chances of naming collisions and specificity wars.

How does the SMACSS methodology help in creating maintainable CSS?

Scalable and Modular Architecture for CSS (SMACSS) is a style guide that encourages modularity and scalability. It categorizes CSS rules into five types: Base, Layout, Module, State, and Theme, each serving a specific purpose. This categorization helps in organizing the CSS code, making it easier to maintain and scale.

What is the significance of the ITCSS methodology in CSS architecture?

Inverted Triangle CSS (ITCSS) is a methodology that helps manage CSS at scale. It organizes CSS into several layers, with each layer having a specific role. This layered structure ensures that the most generic styles are loaded first, followed by more specific ones, reducing the chances of specificity issues.

How can CSS variables contribute to maintainable CSS?

CSS variables, also known as CSS custom properties, allow developers to define reusable values. They can significantly improve maintainability by reducing code duplication and making it easier to make global changes. For instance, defining a color as a variable allows it to be reused throughout the stylesheet and changed in one place.

What is the role of CSS preprocessors in maintainable CSS?

CSS preprocessors like Sass and Less provide features such as variables, nesting, mixins, and functions that aren’t available in regular CSS. These features can greatly enhance code maintainability and readability, making it easier to write complex CSS.

How does component-based architecture contribute to maintainable CSS?

Component-based architecture promotes the creation of reusable, independent components, each with its own HTML, CSS, and JavaScript. This approach makes the code more modular and easier to maintain, as changes to a component do not affect others.

What is the importance of a style guide in CSS architecture?

A style guide provides a set of standards for writing CSS. It ensures consistency across the codebase, making the code easier to read and maintain. A style guide can include naming conventions, formatting rules, and best practices.

How can CSS linting tools contribute to maintainable CSS?

CSS linting tools like Stylelint can help enforce coding standards and catch potential issues before they become problems. They can automatically fix certain issues and provide suggestions for others, improving code quality and maintainability.

Zsolt NagyZsolt Nagy
View Author

Zsolt has been working hard on both his tech skills and soft skills, giving him the opportunity to become a Dev Tech Lead. He has taken these skills to the next level by blogging about his dev journey and creating Dev Career Mastery; a learning platform for developers wanting to expand their soft skills.

css architecturelearn-advanced-cssSitepoint Premium
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week