Writing Long Term Maintainable SCSS

Erik Luetkehans
Artium
Published in
5 min readMar 9, 2020

There are a lot of good techniques and best practices out there about how to write dry, scalable SCSS for when you are developing your website, but what about when you are done? What happens two years later when a new developer rolls on and gets a ticket to fix a “simple” UI bug on mobile, and has to sift through thousands of lines of SCSS to track it down? This article contains a couple of low-effort, high-reward techniques for making your SCSS easily debuggable to others. These techniques are particularly useful if your project:

  1. Is a large-scale project being worked on concurrently by many developers.
  2. Has a high developer turnover rate.
  3. Will be transferred to another team for maintenance.
  4. Product owners want to deprioritize it immediately after launch.

Usually, when you get a bug ticket for a new code base you do not have an intimate knowledge of the file structure and code organization. The first thing you do is find the offending element on a live version of the page, right click, inspect, and try to look up the element class name. The question is: how do we speed up finding that class when we have hundreds of files?

BEM

BEM is a fantastic methodology for naming your CSS classes in an organized way. It gives you an incredible amount of benefits that have been covered ad nauseum by others. The one thing I would additionally advocate is to keep your SCSS files divided as blocks which are named for the component they are in.

As an example, if you have a component file called `todo.js`, then the SCSS file for the unique SCSS in it should be named `todo.scss`, and the block naming inside the file should look like:

.todo_item-title {  font-size: 16px;}.todo_item-title--selected {  background-color: green;}

In this example for `.todo_item-title — selected`, `todo` would be the block or component, which should also be the name of your file, `item-title` would be the element, and `selected` would be the modifier.

Now whenever you are looking for a class that starts with `todo_` you know instantly which file to look in.

Much more about BEM can be learned here: http://getbem.com/introduction/

Keep media queries in rule block scope, not rules in media query block scope

SCSS gives you powerful options for organizing by media query. A pattern I often see and do not recommend is grouping all the css per a breakpoint in one logical block like:

.todo_item-title {  font-size: 16px;}.todo_item-body {  font-size: 12px;  display: flex;  flex-direction: column;}@media (min-width: 400px) {  .todo_item-title {    font-size: 20px;  }  .todo_item-body {    font-size: 16px;    flex-direction: row;  }}@media (min-width: 800px) {  .todo_item-title {    font-size: 24px;  }  .todo_item-body {    font-size: 20px;  }}

Even with just two break points you can see that we are tripling the amount of times we reference a class. In large projects it is not uncommon to have significantly more breakpoints. It is also not uncommon to have the layout of the page change based on breakpoint, as seen with the `.todo_item-body` in the `min-width: 440px` query. In larger files you could have to scroll down for pages in order to see the change. I would suggest grouping media queries by class, so you can easily see the change of behavior of a class as the window shrinks or grows without having to scroll through lines of irrelevant SCSS:

.todo_item-title {  font-size: 16px;  @media (min-width: 400px) {    font-size: 20px;  }  @media (min-width: 800px) {    font-size: 24px;  }}.todo_item-body {  font-size: 12px;  display: flex;  flex-direction: column;  @media (min-width: 400px) {    font-size: 16px;    flex-direction: row;  }  @media (min-width: 800px) {    font-size: 20px;  }}

This way, even if a file had a near infinite amount of classes, one can see the entire expected behavior of an element in one concise block.

Nest conservatively

SCSS gives you powerful tools to organize your SCSS in nested blocks. This can help you keep track of relationships and cut down on overall lines of code. However, when you are initially developing, it can be very easy to over use deep nesting in order to achieve dryness at the cost of maintainability. Consider the following:

.todo {  &_item {    &-title {      font-size: 16px;      &-container {        padding: 4px 8px;      }      &--active {        background-color: blue;      }    }    &-body {      font-size: 12px;      &-container {        padding: 8px 12px;      }    }  }}

Cool! We can see there is very little repeated text here. `_item` is only written once, but is used in almost every class. Now imagine that you needed to change the padding on `.todo_item-body-container` and the todo was a significantly complicated component with many different classes in a project you were not familiar with.

Your first instinct would probably be to navigate to the `todo.scss` folder and cmd + f “todo_item-body-container”. 0 results in file. O.k! It looks like all todo classes are nested in todo, so cmd + f “item-body-container”. 0 results. “Item-body”. 0 results. “body-container”. 0. “container”. In our example it would be two results, but in a large project it could easily be more than 20. Now you have to go result by result and reverse parse the class name.

Another weird effect is that since `&-container` is nested under `&-title`, it almost seems to imply that `.todo_item-title-container` should be a child of `.todo_item-title` when in reality it would be reversed. I would suggest to be conservative with your nesting, and nest at structurally logical points even at the cost of repeated text. Something more like this:

.todo {  &_item-title-container {    padding: 4px 8px;  }  &_item-title {    font-size: 16px;    &--active {      background-color: blue;    }  }  &_item-body-container {    padding: 8px 12px;  }  &_item-body {    font-size: 12px;  }}

As you can see, BEM helps a lot about deciding where to put your nesting. Even though we have repeated more text here, when you have to go to make a change to the `.todo_item-body-container` padding, you can navigate to `todo.scss` and cmd + f “item-body-container” and immediately find the code you are looking for, regardless of file size. The relationship between `.todo_item-title-container` and `.todo_item-title` is also much more obvious.

Extra credit: keep company wide common variables in a package

If you are working with SCSS across multiple code bases across a company, it can be a very good idea to publish your company style guide as an npm package of SCSS variables. It is very easy to include the package in all of your frontend projects, and when the company changes their branded color of blue from `#25c1ff` to `#399cff`, all you have to do is pull the updated npm package, rebuild your project, and push to prod, and you will be in sync with every other app across your company.

--

--

Erik Luetkehans
Artium
Editor for

Cloud architect and full stack developer at Fractal