This is a follow on from my thoughts on a robust CSS methodology for big projects, and will be a more actionable post, based on the decisions I’ve made thus far.
How you sort your code is definitely one of the most important considerations when starting any project. And especially with CSS, because the logical divides aren’t as obvious as they might be with HTML or other languages.
Traditionally to reduce http requests, css is pushed into one big monolith of a file. Thankfully between scss and the Rails asset pipeline we’re using on this project, that’s been largely averted. Nevermind the fact that with http2 there is a compelling argument for many smaller files over one big one.
With that in mind, here is what I believe is an efficient breakdown of CSS files and what each one should contain.
Here’s the basic scss structure, in the assets/stylesheets folder. Please bear in mind that this is built with our current project in mind, and makes a fair amount of allowance for maintaining legacy and new code within one project. If you’re just starting a project from scratch, you should be able to eliminate the /legacy folder as well as /overrides/_defence.scss.
All third-party libraries go here. In our current project that includes Bootstrap, Font Awesome and some Bootstrap plugins.
SCSS files only and handles all the site defaults. This would include setting up color and typography defaults, media mixins, helpers, etc.
These fall into the following files:
- _colors.scss – holds all color variable names. Both general defaults as well as for all themes.
- _fonts.scss – just holds any external font inclusions. I find it simpler to separate this from the typography mixins & defaults below.
- _typography.scss – contains all font stacks, font-weight and letter spacing sass maps (more on this in another post).
- _helpers.scss – all helper/utility mixins & classes – like sticky, left/right align, etc
- _media.scss – media query mixin(s). more on this in another post.
This will hold all component styling. Components are currently divided into 2 primary types:
- Simple Components
- Complex Components
Depending on the number of files, it might be worth having an _index.scss in each root folder that includes all the components there, so that the application.scss file (see below) doesn’t get too cluttered. I don’t see this really being a requirement with any of the other folders really, unless maybe there are a large number of 3rd-party files in /libraries.
These would be all general components not specific to a template file and are usually simple components.
Examples would be buttons, icons, logos, lists, general typography, etc.
All common templates should be in the
common folder, ie:
../components/common and saved with the component name, eg
Complex (or Template) Components
Complex components would be any component that has a single purpose made up of any number of common and complex components.
Ideally, all complex component styling should be strongly coupled to the template component itself. The best way to achieve this would be to have the CSS in the same folder or even file as the rest of the component code. I, personally prefer the separation of each code type to its own file as much as possible.
With the rails asset management, as far as I know, all CSS needs to be in the stylesheets folder, so to ensure tight coupling, the folder structure for the SCSS file needs to reflect that of the actual component, even though they’re physically in different places in the codebase.
Additionally, our code base is broken into template based views, that may contain one or many complex components, so because of that I’ve selected to name the folder containing all the complex components ‘templates‘ instead of ‘complex‘ but feel free to use the naming convention that you feel best reflects your project structure.
Naming convention: all component-specific CSS should be in its own file and follow the same folder structure as the component it is styling.
So if a component file is in :
the SCSS file would be:
The overrides folder will hold 3 main file types.
- Any third-party library changes
There are times that there’s some weird code in a 3rd-party library that needs to be squished or changed. Rather than messing about with the library code (which is never a good idea), rather create a file and override it here.
Follow the following naming convention append ‘-mod’ to the library you’re changing:
E.g. If you wanted to override some styling in
bootstrap-toggle you would create a file called:
In defence of shame.
defence.css and shame.css – both come from some tips I got from this fantastic video/slideshow by Harry Roberts on refactoring css. I highly recommend you have a watch.
This file is specifically used when one needs to override the old site styling (which we inherited) before writing new styling on top of it. The reason for this is so that the new css is clean and remains unaffected by any old code that’s still hanging about. In all honesty, this has had limited use so far, and I find it simpler to, where possible, rather remove the old css. However I’m sure there will be cases where this won’t be possible (because of reliance on old styling in other parts of the app that we haven’t yet addressed), and that’s why I’m keeping it around. The idea is to scrap it as soon as we move entirely away from the old css files.
Similar to _defence.scss, shame is there for all the quick and dirty and old-browser tricks you might need to do but hate doing and really don’t want to muddle your squeaky clean CSS with – all that crabby (!important, etc) code goes here. It’s named in a way that would hopefully push any self-respecting dev to use it as a last resort – it always should be – but sometimes you need a place to hide the shitty code, and making provision for it means that you can rest easy knowing everything else is sexy af.
This is where all the legacy css would go. I don’t really want to talk about it.
This bad boy ties all the other things together and is a staple of the Rails asset flow. It basically serves as an index of all of the above files.
As a general rule, here’s how the files are imported:
- All library files, with the css reset loaded first.
- all.css – all legacy css would go here.
- Any library overrides in the /overrides folder
- overrides/defence – a fat layer of normalising css on top of the old inherited code.
- All /default files.
- All /components/common
- All /components/templates/…
- overrides/shame – sits on top and overrides everything.
Wow, that was a lot more than I expected when starting out with this.. hehe.