If you know what CSS preprocessors are, chances are better than even that you think they’re pretty great – at least when compared with vanilla CSS (and if you don’t know what they are, head over here first).

I started using CSS preprocessors a couple of years ago, and in that time, the way I’ve organized my stylesheets has evolved. And while it might not seem to be a minor point, the way you organize your styles can have an impact on readability, maintainability, workflow and final file size.

My evolution in organization went something like this:

Following the DOM

One of the key selling points of preprocessors like Sass and LESS is the ability to nest CSS rules. So instead of writing this:

.container {
padding: 10px;
}
.container p {
margin: 10px;
color: red;
}

You can write this instead:

.container {
padding: 10px;
p {
margin: 10px;
color: red;
}
}

If you’re familiar with just about any programming language, the nesting helps make it clear at a glance that the rules on the paragraph apply only to paragraphs inside a container.

So, like many before me, I started nesting everything to make things easier to read. However, our increased readability came at the cost of increased complexity, specificity, and code size. When Sass compiled my CSS, it wasn’t unusual for it to contain a thousand rules like this:

.homepage #wrap section#well article p a { text-decoration: none; }
.homepage #wrap section#well article h2 a { text-decoration: none; }

Also, most of the sites I build these days are responsive, which meant (at the time) writing a bunch of absurdly and unnecessarily specific rules for the desktop design, overwriting those rules for the tablet design, and then overwriting those rules for mobile. This resulted in Sass files thousands of lines long – and compiled CSS files that were even longer – effectively negating any readability bonuses.

So what was the solution? Partials!

Breakpoint Partials

Sass partials are Sass files that don’t get compiled directly to CSS: instead, they get imported into other Sass files. So your file structure might look like this:

_colors.scss
_fonts.scss
styles.scss

And the first couple of lines of styles.scss would look like this:

@import “colors”;
@import “fonts”;

The ability to chunk my code seemed like a reasonable way to fix my readability woes. The media query breakpoints I had set up for my responsive design seemed like a natural way to break up my styles – I mean, they’re called “breakpoints.” So that’s the approach I took. My file structure looked something like this:

_desktop.scss
_phone.scss
_tablet.scss
styles.scss

Now instead of one 3,000-line file, I had one 3-line file and three 1,000-line partials. In other words, I had treated the symptoms, but didn’t really fix the underlying problem.

Modular Sass

Eventually, I realized that breaking my tangled Sass spaghetti into functional chunks, or “modules”, was the way to go. Each module of code would affect a specific portion of the site, and would only be as specific as it needed to be. Just because my navbar was inside of my header didn’t mean my Sass needed to reflect that. Instead of nesting like this:

body {
header {
nav.navbar {
ul {
li {
a {
text-decoration: none;
}
}
}
}
}
}

I could easily get away with this:

.navbar {
a {
text-decoration: none;
}
}

Once I started writing my code more modularly, my compiled CSS file sizes dropped dramatically. As a bonus, my shorter code was even more readable. It was much easier to find things in my three partials (desktop, tablet, mobile) as well.

Once I reached this stage, my changes became more philosophical than practical.

Modular Partials

Sass lets you include media queries anywhere in a file, even nested inside the rules they are modifying. It looks something like this:

.navbar {
width: 980px;
@media screen and (max-width: 480px) {
width: 100%;
}
}

Suddenly, having my partials based on media queries didn’t make a lot of sense anymore. I thought about my workflow: if I were going to change something on a site, would I be changing “the mobile version,” or would I be changing “the navbar” across multiple breakpoints? The latter seemed more likely, so I started organizing my partials according to what they were, not when they appeared.

Now my file structure looked more like this:

_article.scss
_footer.scss
_header.scss
_navbar.scss
_sidebar.scss
styles.scss

While this increases the overall size of my Sass a little (having dozens of media queries instead of a few), each partial itself is smaller and more readable.

Mobile-First Modular Partials

Today, I’ve started to take things a little further and thing about the order in which I apply my styles. Generally speaking, mobile designs simpler than desktop designs, and mobile hardware is less powerful than desktop hardware. So why was I writing my desktop styles first and overwriting them with mobile styles, making the least powerful devices do the most work?

So instead of writing rules like this:

.navbar {
// Desktop styles
background-image: url(‘big-fancy-image.png’);
width: 980px;
@media screen and (max-width: 980px) {
// Tablet overrides.
max-width: 760px;
}
@media screen and (max-width: 480px) {
// Mobile overrides.
background-image: none;
background-color: #36c;
max-width: 100%;
}
}

I’m now writing my Sass so that my mobile styles come first, and get overwritten for larger screen sizes, like this:

.navbar {
// Mobile styles
background-color: #36f;
max-width: 100%;
@media screen and (min-width: 768px) {
// Tablet styles.
max-width: 760px;
}
@media screen and (min-width: 980px) {
// Desktop-specific rules
background-image: url(‘big-fancy-image.png’);
width: 980px;
}
}

This way, mobile devices get the styles they need right up front, and can ignore the media queries entirely. This also helps me thing of mobile styles as my base that I can build upon, instead of thinking of desktop as my base that I “strip down” for smaller screens. This seemingly minor shift in viewpoint can have major effects on how you approach your projects.

And this is where I find myself today, though I’m sure it won’t be the final stage in my evolution of preprocessor usage. What about you, Dear Reader? Are you somewhere along this spectrum, or have you found a completely different and awesome process?