A Practical SASS Project Structure

This is an overview of how I structure the `scss` folder of my web projects:

Overview

Directory Structure

/scss
    /1_utils
    /2_exernal
    /3_elements
    /4_form
    /5_sections
    /6_modules
    /7_pages
    _project-settings.scss
    _shame.scss
    legacy-screen.scss
    screen.scss
    print.scss

The Philosophy

The idea is that splitting files is cheap and modularisation is king. Nothing should be included that doesn’t need to be and the cascade is maintained. In practice, this means that rules go from general to specific.

The print stylesheet (`print.scss`) is a first-class citizen and is just as easy to create and maintain as the main screen stylesheet (`screen.scss`). Old-browser hacks and legacy-IE workarounds only get sent to those browsers with `legacy-screen.scss` leaving the main stylesheet free and modern.

When support for legacy browsers is dropped, `legacy-screen.scss` can be removed and the world keeps spinning without a hitch.

Maintaining the Cascade

The selectors and targets of the partials in each folder are more specific and brand-coupled than those in the preceding folder.

For example, the styles in `/4_form/_buttons.scss` would declare some general styles for various button classes, but specific button instances like `.signup-button` would go in the more specific `/6_modules/_signup-form.scss` file. If the signup form needs to be slightly modified for each page that it is presented on, page-level overrides are defined in `/7_pages`. If the `body` element has a class hook, the CSS could appear as follows:

`/4_form/_buttons.scss`:
button[type=”submit”] {
    /* basic button styles */
}
`/6_modules/_signup-form.scss`:
.signup-button {
    /* specific signup-form-based overrides */
}

`/7_pages/_weekly-promo.scss`:

.pg-weekly-promo {
    .signup-button {
        /* page-specific modifiers */
    }
}

After a few years of refinement, I’m confident enough to consider this to be an effective methodology for several reasons:

  • When things change, only the things that are affected by the change need to be modified e.g: when the Weekly Promo page is retired, the signup form module styles never need to be altered; the page-specific overrides can simply be removed.
  • When investigating bugs, the intended scope of a rule is self-evident: if a rule needs to be altered, the selector itself indicates which SASS file needs to be opened for editing.
  • Keeps single-use modifiers out of the generalised class definitions. If your `<li>`s need to have `font-weight: bold` only in the Features List, the code for it should only live in `/6_modules/_features-list.scss`.
  • Permits cross-project code re-use: every web project I work on needs a similar set of boilerplate code like a clearfix definition, removing the default margin from the `<body>` and even things like sticky footers. These can all be flawlessly re-used with simple, single-purpose classes like `/1_utils/_mixins.scss` and `/3_elements/_footer.scss`.

Usage Breakdown

Here’s how this SASS project structure actually works.

The Root-Level Output Files

All the partials and folders eventually compile down into three files: `screen.css`, `legacy-screen.css` and `print.css` created by their respective SASS files in the root of the folder. Each file is filled with a bunch of `@import`s so that each can independently use only what is needs. For example, `print.scss` probably has no use for `/3_elements/_video.scss` so it simply isn’t imported. Each of the files import the partials in the order that they’re needed, as close to the numerical order that the folder structure uses.

The `_project-settings.scss` partial is imported at the top, as the very first partial because it sets up global variables that the rest of the SASS files use.

`_shame.scss` is kept at the root level as a constant reminder to get in there and clean it up, putting things where they need to go. It is imported at the very bottom.

Note to SASS beginners: the reason that `_shame` and `_project-settings` begin their filenames with an underscore (`_`) but `screen`, `legacy-screen` and `print` do not is explained here.

1_utils

Files in this folder generally do not output any code, they define things like colour variables, breakpoints, mixins and placeholders.

2_external

Files in this folder are styles from external sources like:

  • Icon fonts
  • jQuery plugins
  • CSS frameworks & grid systems

It is important to remember that you should keep the contents of these files as close to the authors’ original versions as possible, overriding styles in other partials written by you. This keeps the original files replaceable and allows for easy updating / diffing when a new version of their file comes out.

Common exceptions to this rule include:

  • Stripping out unneeded rules and styles that will never get used
  • Reducing selector specificity when your overrides are getting too strong
  • Namespacing their code with your own

3_elements

Files in this folder are strictly used to set default element styles. This means things like `<html>` styles go in `_html.scss` and basic list styles go in `_lists.scss`.

I always have the following file called `_all.scss` for the `*` selector:

* {
    box-sizing: border-box;
    -webkit-font-smoothing: antialiased;
}

Another rule of thumb is that styles for table elements—`<table>`, `<tr>`, `<td>`, etc.—can all go into a single `_table.scss` file. Additionally, styles for `<h1>` to `<h6>` elements can all go into `_headers.scss`.

4_form

Files in this folder define the basic styles for form elements and input controls. Aside from the basic `_form.scss`, there’s things like `_select.scss`, `_buttons.scss` and `_checkbox.scss`. Custom form elements like drag-n-drop modules and on-off toggles should be defined in `/6_modules`.

Styles for specific forms like signup forms, contact forms and so on should go into:

  • `/5_sections` if the form is significantly large
  • `/6_modules` if the form is not significantly large, but appears on more than one page
  • `/7_pages` in the partial for the page it appears on if it only appears once on the site

5_sections

This is a somewhat difficult folder to define. Things that are ‘sections’ on a website can often be styled up with dedicated HTML5 selector elements (e.g.: the <header> section gets styled in `/3_elements/_header.scss` but sometimes you have more project-specific sections that need be defined like `_quiz-section.scss` or `_comments-area.scss`. These appear in this folder.

6_modules

If you’re used to building CSS components with Atomic Design, modules are known to you as ‘molecules’—bigger than single elements, but smaller than sections. These are the things that can appear in multiple places throughout your site or app and generally have a single purpose. For example:

  • Search Form
  • Search Result Item
  • Contact Form
  • Scoreboard
  • Gallery
  • Testimonial
  • Grid System

In general, if a module only appears once on a single page, it should probably be defined in the page style. If it gets used in multiple places, refactor it out as its own discrete module.

7_pages

Files in this folder contain page-specific styles and overrides that use a CSS hook on the `<body>` or `<main>` element. As mentioned above, if a module only appears once on a single page, it should probably be defined in the page style.

If you have pages that share layouts, this is still the folder to define their styles but instead of duplicating code in both `_about-us.scss` and `_current-specials.scss`, you can use a more generic selector like `_two-column-page.scss` or `_gallery-page.scss`.

Wrapping Up

Over the last few years I have refined my SASS architecture methodology down to what I’ve written here and I haven’t had any major troubles with it. It is compatible with other architecture like grid systems, BEM and SMACSS and is as non-opinionated as possible.

Getting to a particular rule is easy because the folder structure mimics the scope of the ruleset and the sphere of influence that each rule is given is well defined and doesn’t lead to any nasty surprises.

Sometimes the modules folder can contain many more partials than the other folders, but haven’t come across any significant issues with knowing where to find something when I need to.

Keeping many small, single-purpose files is great for maintainability, self-documentation and code reuse; plus source maps practically hotlink to the specific spot you’re debugging.

If you have any suggestions or ideas to improve this SASS project structure, please let me know!

Leave a Reply

Your email address will not be published. Required fields are marked *