A Quick Guide To Modular CSS – Don’t Be Petty, Write Less Spaghetti!

| 8 min. (1559 words)

Are you transitioning from regular CSS to a modular CSS preprocessor?

Or, perhaps you’ve just started using a CSS pre-processor?

If so, you may be able to relate to the following:

  • Writing CSS is easy
  • Writing CSS for a one-off large scale project is easy
  • Writing CSS for a large scale project with multiple people working on it… isn’t.

It’s often the case that there’s no structure. You’re constantly running into cascading problems and having to write classes that undo conflicting parent styles.

Refactoring is a mess, as you’re jumping all over the place. And it’s not maintainable.

I.e. – spaghetti.

However, it doesn’t have to be this way!

This article will help you and your team write maintainable CSS that you can iterate and develop on. I’ll share some techniques that have got me out a messy spot more than once!

Firstly..what is spaghetti CSS and how can we avoid it?

One of the best parts, if not THE best part of using a CSS pre-processor is the ability to create many sub-stylesheets.

Used correctly this is AWESOME, but used incorrectly and this could  be your worst nightmare…

So let’s go into what I call spaghetti:

However, this is the CSS we want:

Let’s look at some common traps I fell into when I started writing scss:

How to write spaghetti code (not good!)

One of the first things I did when I started writing scss was to break apart my main.css file into sub stylesheets using the @import feature.

(tip: if you name your @imports starting with an underscore preprocessors won’t generate a file for them! E.g. @import “_sub-stylesheet.scss”).

This in itself was great, and my second favourite feature.

However, my favourite feature was the wonders of nesting classes.

You may recognize:

// _page.scss
// --

.home-page {
  .button {
    // Behave in a custom way
  }
}

//

This was by FAR my favourite feature of SCSS, I found doing this sped up my spaghetti output by a factor of 10! It was great in the short term, but I wasn’t aware of how it would come around to bite me in the near future.

I wish I knew the problems I was creating for future me.

I thought I was safe.

Then it happened.

Here’s how it went down:

A common element that was used everywhere throughout our site was redesigned. It wasn’t a big change, but because of how I had modified the element to work in certain scenarios, I had to update the element across several stylesheets.

I couldn’t safely delete the:  

Safe to say, I learned my lesson. Here’s what I learned:

How to write better CSS code:

The idea behind modular CSS is to write specific styles that serve a single purpose within a given scope with less general classes you use to mix and match to get your desired effect.

I did this to a point, however I set out some specific rules:

Here’s a hypothetical scenario and how you could approach it:

For all the examples in this post I’ll be using the BEM methodology (one of many modular methods for writing CSS)

For this example:

Variables.scss

A stylesheet for global variables.

Block.scss

“Blocks” are  simple,reusable,standalone block with a single purpose, such as a button / icon / avatar.

Component.scss

Components are reusable, but are more complex that blocks, they often consist of blocks. E.g. accordions / dropdowns / modals.

View.scss

A stylesheet specific to a page.

The Task:

What I’m trying to show in the above graphic is the all too familiar connections created by spaghetti modular CSS (bad).

By nesting classes inside of other classes, I have not only created a specificity battle, but created a reliance on multiple stylesheets. At a small scale this seems manageable, but when it comes time to refactoring and deleting this code, it’s awful – even as the author.

Lots of cross file references, tracking down what’s changing becomes a maze. When it comes to deleting dead code, it’s now also tangles with code that could be being used anywhere. The goal with modular css is to reduce dependencies.

If I wanted to update block on view, I’d have to remember to go to the view to make the change, but then if I reused that style, it’s now not specifically linked to that stylesheet.

Also: I can’t count the amount of times I have been told:

This color will ONLY be used here

Even so, be consistent.

Variables like colors have a very high tendency to be used all over the place, so structuring them in a way that facilitates letting you using them anywhere is key.

Now the same task but modular css:

Rethink the tasks:

One of the first things you have to do when given a list of changes is to  take a step back.

Think about the larger picture with modular CSS.

Instead of making “component” just plain bigger on a specific view, control the component within the component stylesheet – by creating a state for it.

What this means it that you have now created an “option” for the component, not tied to any view, free to be reused wherever you want.

This also keeps all CSS relative to the component contained within a single .scss file.

Writing modular CSS in this way allows you to scale the codebase easily  (and promote reusability) as you don’t have to hunt to find different versions of X, they should all be contained within their own stylesheets (and independant).

Everything being modular also allows multiple people to work on the same files at the same time.

As you can see per the above image, there is no dependence between the stylesheets (Other than variables). This means when “block” is deemed dead code, you can safely delete the file with no cross file repercussions.

Experiment conclusion

Yes the outcome is the same for both examples.

However what’s important to remember is unorganised and messy code (even though fast) introduces unwanted complexity, less options down the track, and promotes duplication if you want to reuse any of the styles and have them somewhat organised.

TIP : To change an element for a specific case, write a modifier class for the element, never change something that was not created in the stylesheet you are modifying.

As another example, let’s take a look at this piece of spaghetti code:

.view .component .block {
  // really specific code controlling block.
}

It’s hard to maintain spaghetti code like the above.

It’s also a performance nightmare.

This small example would require the browser to make 3 fetch attempts across the DOM before being able to render all the changes.

You can read more about this here.

The end result of adding a single selector is miniscule, but multiply this over an entire codebase and you can inadvertently add seconds to your page rendering time!

So how do we get started on writing less spaghetti?

Getting Started.

So, you’re probably wanting to get started.

I recommend the following steps:

  1. Find a set of rules and enforce them
  2. Start with a small project to get used to how things should work
  3. Don’t make exceptions to the rules! If something doesn’t bend the way you want, create a new stylesheet and make the thing you want from scratch.
  4. Try and reduce classes within classes as much as possible (in css that is).

Changes made to a block element should be done so with a class on the respective block or element, not their parent.

If it needs to look different, decide whether it should be done via a state class modifier, or by creating a new component.

_Tip: if you name a scss file starting with an underscore e.g: “class-name” it won’t generate a css file.

A simple folder structure to get you started:

Writing modular css takes a fair bit of getting used to. Start with a small small project.

Rules:

Note: Rules are made to be broken, but do so wisely, and enforce them!

All files are included inside main.scss.

Since every stylesheet is independent you should never need to be including files inside other included files.

This just creates complexity for no reason.

Create 5 primary folders.

Shared.

Layout .

// Reusable styles that change the layout of a page.

Blocks.

// Blocks are stand alone elements, able to be used by themselves as well as by components. Usually created by a single DOM element.

Components.

// Components are reusable, but contain multiple blocks.

Views.

If a page cannot be completed using reusable styles, or you need to create specific styles for ONLY this view, (never to be reused, 100% sure)  add a stylesheet named after the view, and write the css here.

// You’re the best judge of your own system, add / remove folders at will!

A few tools to help you on your way:

In conclusion…

SMACSS

BEM

SUI

Atomic Design

As with most things, there is no silver bullet that will solve all your modular css problems.

The major takeaway from this article is no matter which method you are using, it’s important to make sure you what you are writing is tidy and maintainable, with small modular stylesheets each with their own purpose and that are independent from each other.

And above all,

Don’t be petty, write less spaghetti!