Read time: 7 Minutes
If you have been coding the web for a while (like myself) you’ve probably come across the “lovely task” of how to maintain CSS without losing your sanity. Let’s be honest, even with the release of CSS3, the language evolved a lot and now we are capable of doing things that were only possible with javascript. CSS, at its core, still is a cascade stylesheet and this makes things a bit complicated when your project scales up and is maintained by a team of developers.
A meme is worth a thousand words
I am all about performance. If I can make something work faster, lighter, with fewer requests, I will. When it comes to CSS, I try to keep it tidy, organized and as small as possible. In this article, I will share my approach to achieving this task.
First thing before you start writing any line of code. Pick a methodology. There are already a couple of approaches out there, all of them developed by very smart folks that faced this problem before us. If you don’t know what a methodology is about: they define a set of rules that give purpose to your CSS classes. In this way, you can categorize and divide (modules) code and reuse it as much as possible.
I will explain a bit one of the different approaches you can take. In this case, it will be SMACCS because it’s the one I use. However, you can also see BEM, Atomic, OOCSS. All of them are good.
Stands for scalable and modular architecture for CSS. In a nutshell, SMACSS defines 5 rules:
Base This you can think of a CSS reset. All rules necessary to standardize your CSS project. No classes or IDs in this section.
body, form {
margin: 0;
padding: 0;
}
a {
color: #039;
}
Layout Set of rules to define your structure. These elements are meant to contain modules inside of it. They set boundaries to produce the layout. E.g: a page with a 2 column layout. Main content / sidebar
.container {
width: 960px;
margin: auto;
}
.article {
width: 80%;
float: left;
}
.sidebar {
width: 20%;
float: right;
}
Module Elements that build your pages. Things, like carousels, hero images, buttons, etc. They sit inside layout and should be designed to be a standalone component.
.btn {
background-color: purple;
color: white;
padding: 10px;
}
State Pretty self-explicatory. This is rules that overwrite the default CSS applied to an element to apply a different state. This could be a navigation that is collapsed, a button that was clicked, a field with incorrect information, etc.
/* Following previous button example */
.is-active {
background-color: gray;
}
The last rule would be Theme. However, this is something not too many projects share. I will recommend you to check SMACCS documentation (or book) if you are interested to know more the methodology.
I hope you can see the value of having a foundation and why is so important to start with it. Your project will get a structure that everyone in your team knows and can follow. This approach gives you scalability and organization.
After looking at something like SMACSS you are probably thinking: “well if I and my team are going to stick with a methodology we should probably call things the same way”. YES, you are absolutely correct. Naming conventions have been around since the beginning of computing science, they help teams to align things and reduces time on simple tasks like finding a class or file.
CSS is not the exception. You should be able to read anyone’s code and understand if it is a module or a layout (if you are using SMACSS) as well as if you need to create a new class, there are rules to make sure you follow the style guide. This is all really attached to code standards (that’s a topic of its own). But you get the idea… and please, let’s not fight about tabs vs spaces (I am a tabs guys … ? don’t tell anyone).
The previously mentioned methodologies define naming conventions as well and you can use them if you want. I will give you an example of what I normally do.
CSS
// Module
.nav { // Modules are always on word no hyphens
// ... code
}
.nav--large { // Submodules are at the same label. always use --
// ... code
}
.nav__item { // Subcomponents of a module are always follow by __
// ... code
}
.nav-is-fixed { // State indicates something that's toggled
// ... code
}
HTML
<ul class=nav nav--large>
<li class=nav__item></li>
<li class=nav__item></li>
<li class=nav__item></li>
</ul>
<!-- then javascript kicks in and modifies nav -->
<ul class=nav nav--large nav-is-fixed>
<!-- ... code -->
</ul>
When a project gets setup using this kind of approach. The time invested in debugging is reduced considerably because you know where to find the code you are looking for, what does it do and how it’s called. This is a MUST for any mid-large scale project.
I am sure you are familiar with these ones. However, it’s necessary to mention them. I don’t really know who writes “CSS” anymore. We all are lazy, let’s be honest. No one wants to write more lines of code… well, that’s exactly what our friends the preprocessors are here for.
They will help you to write less code, format it in a different way, implement some basic programming logic and then finally dump a CSS file that can be used by the browser. The most popular preprocessors are SASS, LESS, and Stylus. However, lately, SASS has taken most the market. So if you are not already using one and you are planing to do so… I would say, go for SASS.
I won’t explain how to use pre-processors because there’s ton of information about it. A good start point is the _documentation_ section for each one of them (good and straightforward) or you can read “An Introduction to CSS Pre-Processors: SASS, LESS and Stylus”. However, I will explain the parts I consider important for mid-large projects.
Variables Being able to define variables in your CSS is the key. Large projects are probably going to have a design style guide defining primary colours, secondary colours, fonts, breakpoints, etc. This is the kind of things you want to store in variables and reuse it across your codebase.
//If we rebrand the project and in 2 years the primary color is red. We only need to change it in one place.
$color-primary = blue;
Imports CSS codebase can get big. Break it down into different files that can be imported into a master file. That’s the one who will get compiled and dump the CSS for us. Base your files in your methodology. E.g: if you are using SMACSS, a file for base, layout, one per module, etc.
// Breakdown your codes into smaller files
@import 'base';
@import 'layout';
@import 'module-01';
@import 'module-02';
Functions (mixins) the same way we use functions in any programming language to make units of code that can be reuse. Mixins provide a similar approach for CSS. You can do things like rounded borders, breakpoints, circular images, etc. There are tools with pre-defined commonly used mixins:
// Don't ever write media queries anymore. They are long an annoying.
@include breakpoint( $screen-mid ) {
// ... code
}
Preprocessors are wonderful and definitely make our life easier. However, they can be our worse enemy as well. While things might look really neat and simple in your .scss file. The final .css file might be a complete mess.
This tends to happen when we use nesting more than what we should. The code gets compressed and compiled and ends up being a massive line of repeated CSS selectors for only one rule.
To avoid deep nesting. Use a rule of thumb: no more than 3 levels deep.
In the second part of this series we will be discovering the other key elements for managing CSS in mid-large scale projects:
Javascript Task Managers
PostCSS
Testing
Libraries
Thanks for reading and happy coding.
Stay up to date with emails about new services & other news