CSS Architecture — Folders & Files Structure

CSS Architecture — Part 2

Elad Shechter
Jun 3 · 8 min read

One of the essential things in every programming language is architecture, i.e., how the code is divided into file and folders. Somehow, however, CSS was left in the corner, and many developers don’t take the time to plan its architecture properly.

Before we start, some words on who I am:
My name is Elad Shechter and I’ve been developer for 13 years. For the last nine years, my day job is CSS/HTML Architecture.

In this post, I will show my guidelines in defining the CSS architecture, based on my many years of experience.

Side note: nowadays, a proper project uses a CSS preprocessor. In this post, I will be using the SASS preprocessor.

I divided this post into sections corresponding to the main elements of my architecture. My projects’ basic structure consists of a configuration layer and a content layer; the content layer is made up of other layers, the main one being the partials layer. This layer contains elements, components, sequences, and sometimes entities.

Basic Structure

Besides being useful for the separation of concerns, this division will help you build a CSS architecture even when you have more than one website. Architecture for multiple sites is something I will discuss in my next post! You are welcome to follow me on twitter or medium to get updated when it’s published.

The main.scss connects both those files.

Main SASS Folder:

sass/ 
|
|- framework/
|- _config.scss
|- _local.scss
|- main.scss

main.scss file:

@import "config";
@import "local";

Configuration Layer (_config.scss)

To achieve a well-constructed project, I divide the configuration into smaller files according to their logical function.

Example:

  • CDN variables
  • Colors Variables
  • Responsive Design Breakpoints Variables
  • Language Support Variables
  • Main Z-Index layers
  • Other variables which don’t fit into the other parts.

I can’t accommodate all types of configuration, so if you see that your project has more functions, break them into more files.

framework/
|
|- config/
| |- _common.scss
| |- _cdn.scss
| |- _colors.scss
| |- _directions.scss
| |- _breakpoints.scss
| |- _layers.scss
|
|- local/
| |- Folders and Files
|
|- _config.scss
|- _local.scss
|- main.scss

Content Layer (_local.scss)

framework/
|
|- config/
| |- config files
|
|- local/
| |- _mixins.scss
| |- _resets.scss // normalize + resets + typography
| |- _fonts.scss
| |- _icons.scss // font icons/SVG icons
| |- _utilities.scss
| |- _grids.scss // common layouts
| |- _partials.scss // elements/components/entities/pages
|
|- _config.scss
|- _local.scss
|- main.scss

The content layer contains styles belonging to many different logical parts, such as resets, fonts, icons, etc. Even if we divide it into the minimum number of files, we could get to 7 or 8 files. In some cases, it’s better to divide them into even smaller parts so that the .sass files never get too big, i.e., not more than 50 rows if you write your style definitions in one row per selector, and no more than 200 rows if each definition takes a whole row.

Here are some examples:

Mixins layer

framework/
|
|- local/
|- |- mixins/
| | |- _trim.scss
| | |- _rotation.scss
| | |- _prevent-select.scss
| | |- _break-word.scss
| | |- _scrollbar.scss
| | |- _screen-reader.scss
| |- _mixins.scss

_mixins.scss:

@import "mixins/trim";
@import "mixins/rotation";
@import "mixins/prevent-select";
@import "mixins/break-word";
@import "mixins/scrollbar";
@import "mixins/screen-reader";

Reset Layer

framework/
|
|- local/
|- |- resets/
| | |- _normalize.scss
| | |- _reset.local.scss
| | |- _typography.scss
| |- _resets.scss

_resets.scss

/*resets*/
@import "resets/normalize";
@import "resets/reset.local";
@import "resets/typography";

I Wrote a more detailed post on CSS Reset & CSS normalize — “CSS Normalize or CSS Reset?!”

Partials Layer (_partials.scss)

framework/
|
|- config/
| |- config files
|
|- local/
| ...
| |- _partials.scss // elements/components/entities/pages
|
|- _config.scss
|- _local.scss
|- main.scss

Because the partials layer is so big, I divide it into smaller logical inner layers, somewhere between to 3–5 files. The number of files can change between projects or at your discretion.

In this layer, the order of the @imports is critical because there are sometimes dependencies between basic layers and more complex components layers. Since the sequence is so important, I give every main layer a prefix number which represents its order of importance, from most generic to most specific.

framework/
|
|- local/
| |- partials/
| |- 1-elements/
| |- 2-components/
| |- 3-sequences/
| |- 4-entities/
| |- 5-pages/
| |- _1-elements.scss
| |- _2-components.scss
| |- _3-sequences.scss
| |- _4-entities.scss
| |- _5-pages.scss
| |- _partials.scss // elements/components/entities/pages

_partials.scss:

// from most generic to specific
@import "partials/1-elements";
@import "partials/2-components";
@import "partials/3-sequences";
@import "partials/4-entities";
@import "partials/5-pages";

How to determine where in the _partials.scss layer to put your style

The definitions in this layer are divided into several types:

It’s important to put every part in its own file. This way, you can easily control these base styles, without worrying that they might affect other parts of the CSS when you want to change those styles.

Example for _1-elements.scss file (part of _partials.scss)

/*common*/
@import "1-elements/common-links";
@import "1-elements/titles";
@import "1-elements/common-popup";
/*Buttons*/
@import "1-elements/common-button";
@import "1-elements/button-icon";
@import "1-elements/button-tabs";
@import "1-elements/tooltip-button";
/*forms*/
@import "1-elements/select-row";
@import "1-elements/forms";
@import "1-elements/search";
@import "1-elements/search-result";
/*tables*/
@import "1-elements/common-table";
@import "1-elements/table-summary";
@import "1-elements/table-links";
@import "1-elements/table-filtering";
/*others*/
@import "1-elements/system-alerts";
......... a lot more...

(Break everything (!) into small parts)

Components- are bigger partials. I use them for parts like main-header, main-footer, navigation, breadcrumbs, etc..

The Components’ HTML can contain Elements partials inside them. Sometimes the component will not affect this Element, and occasionally it will, according to your needs: When you want an existing element to behave differently in a component, you must include the component after defining the element so that in that component, the element will get its new specific definitions. As I wrote before, when I divide the _partials.scss layer into those main layers, I add prefix numbers at the beginning of each layer to indicate that there are dependencies between those layers. In this way, we ensure that cascading styles work correctly.

// from most generic to specific
@import "partials/1-elements";
@import "partials/2-components";
@import "partials/3-sequences";
@import "partials/4-entities";
@import "partials/5-pages";

Sequences- are of a list of articles. They usually appear on news sites, blogs, or any site that has a list of reading items. Sequences may have partials made of elements or components inside it, similar to elements in components that we talked about before.

Entities and Pages partials

Entities- I use these when using elements, components, or sequences whose styles aren’t 100% the same. I add another class name to the element, component, or sequence — in addition to its element, component, or sequence class — and that enables me to apply different styles to it. The class name starts with an ‘e-’ to represent an entity,

My rule of thumb is that you can only add one entity to an element/component/sequence. If there is another case of such an entity differing from the generic one, it is better to create another entity instead!

Example:

<section class="common-popup e-datepicker-popup"> </section>

Other than that, you can add as many CSS utility classes as you want.

<section class="common-popup e-datepicker-popup u-hide"> </section>

Pages- every page on your website can be an entity. In this case, the class should be added to the body element or to the main element that wraps everything. The class name should start with a “p-” for example: “p-homepage” or “p-news” etc.…

This class can affect every element, component, sequence, or entity on the page.

This approach is better avoided if you can, but sometimes in real life you have cases like this.

<body class="p-homepage"></body>

To Summarize

If this interests you, you’re welcome to follow me on twitter or medium.

My CSS Architecture Series:

  1. CSS Architecture — Folders & Files Structure
  2. CSS Architecture for Multiple Websites

Final Words

More of my CSS posts:
New CSS Logical Properties!
CSS Position Sticky — How It Really Works!

Who Am I?
I am Elad Shechter, a Web Developer specializing in CSS & HTML design and architecture. I work at Investing.com.

You can contact or follow me:
My Twitter
Facebook
LinkedIn

You Can find me in my Facebook groups:
CSS Masters
CSS Masters Israel