I’ve put together 8 rules that help me keep my CSS clean, well-written, and in line with best practices. When combined, these rules will give you the ultimate template for good, scalable CSS architecture.

CSS is an important aspect of every modern web application. But for web app developers, CSS is often overlooked, or considered less important when compared to coding and programming behind the app. But the fact is that CSS and coding are pretty much the same animal—it’s easy to write code that seems to work, but closer inspection shows that tons of things are written poorly.

I’ve put together 8 rules that help me keep my CSS clean, well-written, and in line with best practices. When combined, these rules will give you the ultimate template for good, scalable CSS architecture.

Rules

0. Use preprocessors

Creating a maintainable and DRY CSS code without any help from preprocessors makes life hard. That’s why you rely on a good preprocessor to start off. There is a reason behind the phrase “CSS with superpowers”. A good preprocessor equips you with bunch of great fundamental features that keep your code cleaner and easier to maintain. At Netguru, we love Sass with SCSS syntax (it’s compatible with pure CSS), but you might also want to try Less or Stylus.

1. Define your style guide

You probably use a style guide for JS or Ruby. There should be no exception with CSS. It’s extremely important to start project implementation by defining the style guide. Each style guide should cover every aspect of syntax, rule ordering and naming conventions. Sounds like a lot of work? Don’t worry, a lot of great companies keep their CSS style guides public, so you don’t have to start from scratch. Sass Guidelines is also a great place to start.

Tools

I believe that you should automate your processes whenever possible. Luckily, there are several tools that make sticking to style guides easier. Try scss-lint for local development (there are Sublime and Vim plugins available as well). When you’re hosting your code on Github, I highly suggest trying Hound. It’s a great tool which reviews Github commits or pull requests for styleguide violations. Since Hound relies on scss-lint, you won’t have to create different config files.

2. Determine supported browsers

Making sure that a website works properly in all browsers might be pain in the ass, especially if you need to support one of the old IEs. Start with determining in which versions of IE your app has to:

work properly,

look fine,

reflect its exact design.

Whenever it’s possible, use power of CSS (for shadows, transforms etc). Make sure it works properly in all modern browsers by adding vendor prefixes. Help yourself by using Autoprefixer - it does the dirty work for you.

3. Divide your code into small pieces

Try to keep your CSS files short and clean (i.e. under 100 lines of codes). Divide your code into components and views. If you’re reusing the same objects across the site, it’s perfect candidate for components. If your design is unique to a site, define it in one of views stylesheets.

4. Use variables

It’s a good practice to avoid hardcoding values when redundant. Variables provide better control and good limitations to your code. Use as many variables as necessary - you’ll end up with static CSS anyway. Colors and fonts properties ( font-weights , font-families or font-sizes ) are must-haves.

Variables are also extremely helpful at keeping control over z-index values. Keep all z-index values in one file, so you can quickly compare or change them if needed. First, define variables for each z-index value:

Then, create _z-index-variables.scss and set values using base z-index variables:

This way you have a handy overview at all layers.

5. Use mixins and extends

Another Sass superpower. They really help to keep your code DRY - nothing more to add here, I guess! If you’re not familiar with mixins or extends, read about Sass features and kicking off UI development.

6. Use vector resources

More and more devices come with high resolution screens nowadays. To provide a sharp look for your app on Retina displays, use vectors instead of static images. Play with SVGs and icon fonts whenever possible. They’re pretty awesome since you can easily change color or size without creating separate files, which results in smaller data sizes.

7. Use frameworks

...but use them the smart way. Don’t include Bootstrap or Foundation as it is. Use the power of Sass here as well. The following is the pattern I use for customizing Bootstrap. Start by a creating framework directory. The structure should appear as follows:

Components

Import only the components that you actually need. You can find the full list of Sass components on GitHub. Comment out files that you’re not going to use - it will result in smaller production stylesheets.

The code of each component should come directly from GEM or NPM/Bower packages. This helps to keep your codebase up to date with the framework.

Variables

Popular frameworks like Bootstrap or Foundation are highly customizable. Bootstrap has its own file with variables. Notice that each line ends with !default Sass flag. It means that you can override this value easily (you don’t have to care about the order of imports). The pattern for overriding is extremely simple. Create _variables.scss file, reflect the content of original Bootstrap file and comment it out. If you want to change certain value, removing !default flag will do the trick:

Overrides

Unfortunately, if you have a custom design, you won’t be able to change everything with variables. Sometimes standard overrides are the only way. A good practice is to keep overrides organised the same way as framework components. That way, in framework/overrides/_navbar.scss you override the navbar component and navbar only.

The result

Combining all these rule lead me to following style structure:

To complete the process you have to import files to your app. I follow the pattern by combining all the files into one production CSS file (remember to prepend file name with underscore so Sass knows it’s a partial). The order should look as below:

Start by importing z-index and custom variables so that you can use them as overrides in framework variables. Import all framework components with overridden settings after that. Continue with breakpoints vars (you probably want to use framework variables here) and the utilities directory so you can use your helpers when creating framework overrides. Finish with importing component and views (in that order so you can override component per view if needed). Import each of them one by one in order to have full control over the order.

That’s it! This is my recipe for writing good and scalable CSS architecture. I hope the rules and overview at the structure pattern will help you to write better and cleaner code. Feel free to share your thoughts and questions in comments!

If you like the pattern I've described, check out Bootstrapper - the gem for Ruby on Rails apps that will generate file templates for you.

This topic was originally covered at Frontownia meeting in Poznań - here's my presentation on CSS architecture.