25th September, 2015. The methodology of this post has now been updated, expanded and detailed more fully in my book, Enduring CSS, available from Leanpub.

When architecting CSS for a large scale project it’s a common aim to abstract visual patterns for re-use, DRY out code and normalise our designs as much as possible. However, for rapidly changing projects, I’m no longer convinced those principles should necessarily be followed to the nth degree, nor that they offer the biggest wins.

This post describes what I consider the most advantageous practices and approaches when authoring CSS for a rapidly changing, large scale web project.

Due credit: Nicolas Gallagher is always ahead of the game when it comes to thinking about CSS implementations at scale and I took and adapted large elements (specifically code organisation by component) of this approach from his work. I’d been name-spacing components for some time (and I’m therefore claiming pseudo multiple discovery) but the approach of organising code by component is taken entirely from hearing him talk on this matter.

This post won’t be covering the actual building of visual components: how to initiate animations and transforms, how to structure DOM elements for maximum effect, the best units of measure to use, how to specify different font-stacks for different situations – that’s all stuff for another post (which I probably won’t get chance to write for another 9 months as another book needs to be written).

What this post does attempt, is to encapsulate my current approach to writing CSS for enduring web projects. It will cover essential tooling, preferred project structure and my current CSS authoring methodology (something I’ve semi-jokingly given the acronym, FUN!).

This is a long one, hence the ‘index’:

First up, essential tooling:

Technology and tooling

Capabilities and approach are important, the technology is not

When authoring the CSS for an enduring project, the technology used to produce the CSS should be largely immaterial. We should always be aware that a better or more efficient tool may become available to achieve our aims and when possible, and if preferable, it should be embraced.

It doesn’t matter whether Sass, LESS, Stylus, Myth or any other pre-processor is employed to create the style sheets. The authored style sheets should be as easy to migrate to another meta-language as possible, if and when needed.
Furthermore, the pre-processor employed should best serve the needs of the project as a whole – not the preferences of any individual author. That said, there are some necessary capabilities for the pre-processor so we will cover that (briefly) next.

Pre-requisites for pre-processors

I consider a pre-processor for style sheet authoring essential. This allows a differentiation between ‘authoring’ style sheets (the style sheets that the author writes in their pre-processor of choice) and the ‘resultant’ style sheets (the compiled and minified CSS that gets served to the user).

Despite stating that a pre-processor is essential, the requisite features needed are fairly trivial:

  • variables (to mitigate human errors with colour picking and specifying constants like grid measures)
  • fragment/partials of styles (to facilitate one-to-one parity with a feature branch or template)
  • basic mathematic operations (to negate reliance on ‘magic’ numbers)
  • colour manipulations (to allow consistent manipulation of the aforementioned variables)

All other abilities are considered non-essential and should be appraised particular to the needs of the project.

Build system

A build system must also be available that can run automated ‘house keeping’ on authored style sheets. The human factor should be eliminated wherever possible and tools employed to do mundane tasks more accurately. Typical build tools include Grunt, Gulp and Brocolli to name just a few. Just as there is no universally ‘right’ pre-processor, so there is no universally ‘right’ build tool.

At the time of writing, typical examples of the kind of house keeping tasks needed to be performed on style sheets by the build system may include:

  • Linting (e.g. for Sass it might be scss-lint, to enable code conformity and prevent non-working code reaching deployment
  • css-comb, to provide any pedantic normalisation of CSS presentation not catered for with a lint tool such as the ordering and spacing of declarations
  • Autoprefixer, to enable fast and accurate vendor prefixing and prevent vendor prefixes being present in the ‘authoring’ style sheets

With that out of the way, let’s deal with the specifics of how I feel it best to write CSS for enduring and rapidly changing projects.
First I’d like to explain the way (and why) I currently architect my CSS (and how it differs from current popular approaches) before getting onto organisation and how the files within a project can actually be stored and served.

Writing CSS

Currently, popular thinking tends to place significant emphasis on writing DRY code, abstracting styles as much as possible and having the smallest possible CSS codebase with which to work. My own approaches are, in some cases, at odds with some of those popular principals. Here’s why.

Typically, my foremost goal when writing CSS for enduring and rapidly changing web application is long-term maintainability. As a concrete example; being able to delete an entire Sass partial (say 9KB) in six months time with impunity (in that I know what will and won’t be affected by the removal) is far more valuable to me than a 1KB saving enjoyed because I re-used or extended some vague abstracted styles.

Furthermore, I find modifying existing component abstractions to build new ones too slow. I love using CSS abstractions that are truly utility in nature but taking abstractions for a (slightly) similar existing component and attempting to then modify them to achieve a new goal usually takes far longer than just building what I need to from scratch. I suppose that would loosely be the BEM approach. Like all great work I’ve taken a lot from BEM but it just doesn’t perfectly fit my needs.

This is in some way because rapidly changing projects result in iterating designs that may have many small differences from previous versions. Sure, any new designs should be similar and normalised as far as possible (and we should fight to ensure that any new design elements are different because they need to be, not just because someone wants them to be) with existing styles but sometimes they need to be subtly different; and it should be easy for me/you to accommodate that for the designers I/you work with.

In summary, I find writing styles specific to the design at hand, faster and preferable than adapting heavily from a vague abstraction.

I’d like to be clear that I’m not saying don’t look for oft-used visual patterns and abstract them for re-use. But such abstractions should be pretty low-hanging fruit; what I term utility or single responsibility styles (more of which shortly).

For me, a larger total CSS codebase, made up of components that are in many respects insulated from one another, is preferential to a smaller CSS codebase made up of inter-dependent and intrinsically related styles. Hopefully I can justify and legitimise this stance further shortly.

FUN!

I spend a lot of time naming things. As you write CSS, you do too. I’ve tried all the popular approaches of CSS architecture and none of them quite fit for me. By eating my own dog food and embracing Ping Cing Do I’m currently naming the approach I favour as FUN. This is an acronym for the loose methodology of my favoured approach:

FUN:
– Flat hierarchy of selectors
– Utility styles
– Name-spaced components

Flat hierarchy of selectors

The first core ingredient of FUN is the adherence to using single, ‘flat’ hierarchy, class-based selectors. The benefits of only making selectors as specific as needed have been well documented. For me the three biggest wins come from :

  • Use only classes for selectors except in specific circumstances
  • Never nest selectors unless essential
  • Complete avoidance of IDs as styling hooks

Beyond that, I pretty much don’t give a rat’s ass about the selector used – I don’t think the type of selector used makes any realistic difference, speed wise to a web site/app. If you can sensibly worry about the speed of your CSS selectors after using predominantly flat, class-based selectors, you deserve a day off.

That’s as complicated as the F part gets!

There are patterns with pre-processors that allow you to nest in the authoring environment but produce flat hierarchy in the compiled CSS. I’ve done it both ways and documented my feeling on this more thoroughly elsewhere.
Ultimately I like a one to one parity between the HTML classes in the templates/markup and the CSS selectors in the style sheets; I just like the immediacy of it. Again, there is no right answer here. This is a choice. Make a decision on how you will do this on your team and enforce the decision; it’s confusing to have it part one way and part the other so avoid that scenario at all costs.

Utility styles

Utility styles are single responsibility styles. w100 would set width: 100%;, Tbl would be display: table; table-layout: fixed;. They should have no reliance on other selectors or specific structures.

I’ve found it very useful to abstract text styles in some instances and it’s possible to argue these could be termed utility styles also. For example,txt-Cart_A would be a text name-space item, that is intended for use in a shopping cart and it’s the A variant. I wouldn’t specify font-families there but font-size and colour – and occasionally font-weight.

Utility classes should generally get employed when you can be certain of predicaments. For example, I wouldn’t want to add w100 to an element if I was unsure whether or not the item needed to be 100% width at all viewport sizes.

Your utilities will, and should, be different than mine or anyone else’s.

Some people prefix their utility styles with a `u`, for example `u-100`. However, name them to your own convention. For me, if it is lower case with with no hyphens either side, it’s a utility style.

The only rigid rule with the utility styles is that once made and used, they cannot, ever, be amended or removed. Make as many utility styles as you need but ensure they can be used for as long as you can possibly imagine as they will sit in the CSS of the project for EVER.

Name-spacing components

The third and final core tenet of our tri-pronged CSS methodology is the name-spacing of visual components.

Name-spacing the CSS of each visual component can be used to create some form of isolation. By preventing name collisions with other components, chunks of CSS can be more easily moved one environment to another (from prototype to production for example).

My preference is a simple 2–3 letter namespace for each component. Building a shopping cart? Try .sc- as your namespace prefix. Building the next version of that same shopping cart? That’ll be .sc2- then. It’s just enough to isolate your component styles and allow the styles to be more self documenting. For example, a wrapper for the shopping cart could be something like .sc-Wrapper. Is there a remove item button? Something like .sc-RemoveItem would be suitable.

I’m still enjoying the naming standard I documented here but the important point is that is doesn’t matter what convention you adopt; just stick to it and enforce it.

As name-spaced components are almost guaranteed to not leak into other components it makes it incredibly easy to build out and iterate on new components as new design requests are received. It affords a hitherto un-afforded blanket of impunity.

This approach however is not without cost. This approach has greater potential for code duplication (you may be styling one item in a component that could be abstracted and easily used in another component) but I find it results in far more maintainable code – whole components can be removed in the safe knowledge that their removal will not affect others.

In some ways it is the opposite of DRY; we are gaining a degree of component isolation at the cost of verbosity.

Don’t I care about CSS bloat?

Yes, I do. However, in the situation of a rapidly changing and enduring project, where many different hands have, and will, be on the CSS, my empirical findings have been that more CSS bloat accumulates due to author deletion fear (“I don’t know what that’s for so just leave it in”) than duplicated styles.

It’s likely that CSS authors are more likely to simply add to existing CSS than risk removing huge swathes of it because it’s difficult to be entirely sure what will be affected.

Consider an example. Suppose a component of a web application is deprecated, and you’d like to remove the associated code (we will cover how this scenario relates to templates and any associated JS in a moment) without affecting anything else. This usually poses some difficult questions: where are the CSS rules that are no longer needed? Are they in one file? Many files? It’s often a case of resorting to ‘find in project’ in the text editor. Even then, how can you be sure that nothing else in the HTML/templates is relying on those styles? After all they are abstractions, intended for re-use where possible.

There are tools that are in their infancy (at the time of writing) that attempt to address this problem: UnCSS being one such example. I’m watching them with great interest as it’s potentially another task we can defer to machines in the near future.

However, if the requisite styles for each component are name-spaced they can be removed easily; even more so if the style sheets are ‘partialed’ by component or feature (I sometimes create a partial simply to use alongside a feature branch in Git). To exemplify, imagine that all my name-spaced component styles for a shopping cart are saved into a single partial: _sc-shopping-cart.scss.

To further aid easy removal of old code and components, organising project files by these components goes a long way to isolating code. As an example, if I finish writing CSS for shopping cart v2, I can be fairly confident that the partial(s) relating to v1 of the shopping cart can be removed from the project with no ill effects. Now, if only the templates/HTML and relevant JS were all in one place alongside the stylesheets. Perhaps they could and should be.

Project Organisation

Storing related files

It’s a common pattern to split up files in a project by technology type. Typically:

my-project/
- html/
- js/
- sass/
- css/

The rub though is that beyond a certain point, even giving the files related names, it’s difficult to hold the notion of how each style sheet and template relate. There might be 80+ Sass partials in the sass folder and 50+ template stubs in the html folder.

It then becomes increasingly necessary to rely on ‘find’ in the text editor to find any templates that a certain class is being used on. The same is true in reverse; ‘find’ is needed to locate the partial(s) that contains the styles needed for a certain component template. It doesn’t make things unworkable, just inefficient and requires a little mental orientation to remember what goes with what.

I therefore favour a situation whereby rather than organise by technology type, files are organised and grouped by visual component. So, instead of this:

html/
- shopping-cart-template.html
- callouts-template.html
- products-template.html

js/
- shopping-cart-template.js
- callouts-template.js
- products-template.js

css/
- shopping-cart-template.css
- callouts-template.css
- products-template.css

We aim for something like this:

shopping-cart-template/
- shopping-cart.html
- shopping-cart.css
- shopping-cart.js

callouts-template/
- callouts.html
- callouts.js
- callouts.css

products-template/
- products.html
- products.js
- products.css

It’s a seemingly unimportant dichotomy but brings the following benefit:

The code for each component becomes physically self-enclosed. Then, on our enduring project, when features need changing or are deprecated, all associated code for that component (styles, HTML and JS) can be easily updated/removed.
With the exception of truly ‘global’ utility CSS, all code that relates to the presentation of a component should be including in the partials that sit alongside the HTML/JS of that component.

When organisation by component isn’t possible

It’s not always practical to contain all related component files in a folder. However, naming all partials according to their component gets you some of the benefits. For example: _partials/_components/_shopping-cartv2.scss for the styles pertaining to our fictional v2 of a shopping cart.

Brief considerations on CSS delivery

In early 2013 IIya Grigorik gave a fantastic talk Breaking the 1000ms time to glass mobile barrier. Key for our discussion here is the suggestion of putting critical ‘above the fold’ CSS (that would block the critical rendering path) inline in the head of the HTML.

It’s an approach being made popular at the time of writing by the Filament Groups How to make RWD sites load fast as heck.

However, having tried it shortly after IIya’s initial talk, it’s not something I can entirely jump on board with. Principally because whilst the initial load of that page will be quicker (and it is), subsequent visits will suffer unnecessarily.

With a traditional approach, if a separate style sheet was downloaded and cached that initial ‘above the fold’ CSS never has to be fetched again on subsequent page loads.

It’s not like this is news to people, it’s just the main reason I’m against this approach. The other option is loading CSS in afterwards with JavaScript but I don’t like relying on JavaScript to get my CSS on the page (unless the benefits are sizeable).

If you want the absolute fastest possible first page load, at the expense of all other considerations, the aforementioned approaches are your Huckleberry.

Personally, I favour a more conservative, and traditional approach:

Different areas of a large application or web project often need different, often unrelated, CSS.
In this scenario it makes little sense having a single ‘styles.css’ file containing every possible style needed (for arguments sake, suppose that file weighs in at 80KB) when only 20% of the different areas of the site require between them 60KB of those styles.

Any significantly different areas of the site should get their own style sheet. As everything (as far as possible/practical) is split into ‘component’ partials we can better facilitate these individual style sheets.

Suppose we have an offers ‘page’. The contents of that might file can be compiled from the pre-processor with a subset of partials:

offers-page.css (total weight 45KB):

@include "core";
@include "_components/forms";
@include "_components/login";
@include "_components/callouts";

Whereas the home page may only need this:

home-page (total weight 20KB):

@include "core";
@include "_components/nav";
@include "_components/home-offer";

Note: you could also use file Globbing to import sets of related styles/components if you have further degrees of granularity in your partials. For example:

@include "_components/login/**"; 

While it means more files for the browser to cache (there isn’t just one ‘styles.css’ that services all possible destinations a user visits) each destination enjoys a smaller CSS footprint and therefore faster initial load time (not up there with inlining critical CSS but some way towards it). There are benefits in each approach; I don’t believe either is ‘right’ – it’s merely an educated choice you have to make.

That pretty much concludes my current approach.

However, I think it’s often illustrative to document what doesn’t work as well as what does; to potentially save you future/present enduring CSS author, from repeating any of my dumb mistakes.

Here is a non-exhaustive list of what I consider common pitfalls when writing enduring CSS.

Common CSS authoring pitfalls (I’ve been in them all)

Don’t neglect developing your own naming convention

If I could recommend only one thing out of all this to improve the maintainability and understandability of CSS code, enforcing a naming convention would be it. There is no ‘right’ naming convention. There is only a naming convention that is right for you. The current de facto standard is the classic BEM syntax. This has been documented heavily so I won’t repeat it here.

I would merely add that one shouldn’t adopt that syntax wholesale before prodding it with the stick of cynicism. Does it match the way you work? Does it seem immediately clear to you?
I’ve documented my own variation on that syntax elsewhere. Here’s the short version:

[namespace]-[ComponentPart]_[Variant]-[optional-adjuster]

So, a ‘real’ selector might look like this:

sc-Wrapper

Or this:

sc-InnerItem_Odd

This is unlikely to suit you either. So spend some time thinking this through. Try building out a few components with different syntaxes. See which one seems most immediately sensical. Ask your team mates, even those who seldom touch the CSS, which they prefer (take their comments on board if it matches your own preference and discard it if it doesn’t ;)).

Your property and values can be changed easily in future but the naming convention for classes becomes the very bones your styles will hang upon. It affects not just the readability and intelligibility of the selectors but also the HTML classes that will litter your templates/markup.

Until you have done it wrong or neglected this step a few times, it feels like a waste of time. Avoid it at your peril.

The horror of perfect abstractions a.k.a. name with intent

You’re likely smarter than I so you wouldn’t do this. But I did.

Once upon a time I created myself a little project called ‘Pst!’. It was an acronym for Position Structure Theme. The idea was I would do away with semantic class names. Instead any element could be styled with a combination of a position class, a structure class and an optional theme class. An element styled with ‘Pst!’ might look like this in the HTML:

<div class="p1 s3 t4">Content</div>

Lovely! It was compact, there was no time wasted thinking of a sensible name for the next selector (you just appended a number as you went), it gave terse markup but, and here’s the crucial point:

It was unintelligible.

Can you imagine a whole page of markup with only those kind of HTML classes? There was no way to discern one piece of DOM from another.

Then another shortcoming – responsive. How to determine what a s3 should do at what viewport size, and inside another structure. In short: a horrid, horrid experiment.

Which brings me to an obvious point. Name with intent. I’m a fan of classes like .WarnUser and .sc-CurrencyDropDown – hitting the intended use right on the nose (and therefore able to be visually different in different contexts). I’m yet to try anything that has convinced me this is not the way to go.

Don’t specify vendor prefixes in the authoring style sheets

Do not do this. The level of browser support you require will change over time (resulting in redundant code in your authoring style sheets). The prefixing of CSS properties can be handled in a couple of lines with an automated tool and will be more accurate than you. It may take you an afternoon to get this set-up. Do it. It will be worth every moment.

Avoid library mixins

There are many pre-processor libraries that provide ready rolled ‘mixins’ for accomplishing standard CSS tasks (clearfixes, background gradients etc). Don’t use them. Author wherever possible in W3C compliant CSS code. This makes the authoring styles more portable if you decide to switch pre-processor or copy code to a new project and reduces dependency (as a bonus, particularly if using Sass, it can also significantly reduce compile time).

Don’t put markup samples in CSS comments

Comments are good. Indeed, writing lots of meaningful comments is encouraged. However, refrain from entering examples of intended markup in the comments of style sheets. They immediately create a scenario where information is likely to become obsolete and confusing. Instead, the template stub that sits alongside the style sheet should provide all the markup. As this template is necessary for the application to function, it is by nature always up to date and provides a more meaningful reference.

Avoid ‘clever’ code abstractions

Don’t write impenetrable looking code. CSS is a declarative language so try and keep the authoring style sheets as accessible as the resultant CSS.

Mixins and logical loops are sometimes preferable and advantageous (they can greatly reduce verbosity and repetition in the authoring style sheets) but don’t needlessly complicate simple needs. Even Hugo Giraudel, the Sass nutter draws the line somewhere.

For example, creating a number of utility table width styles could be achieved like this in Sass and typifies the limit of what I deem sensible in terms of complexity:

/* ==========================================================================
   Table modifiers
   ========================================================================== */
$widths: 5 10 20 30 40 50 60 70 80 90 100;
%Tbl-base {
    display: table;
    float: left;
    vertical-align: middle;
}
@each $width in $widths {
    .tbl#{$width} {
        @extend %Tbl-base;
        width: $width * 1%;
    }
}

As a counter example, a mixin for creating buttons that requires three or more arguments to be passed just to set border styles, background colour and text size is probably a needless over complication.

Be wary of @extend

This final one is very Sass centric. Don’t extend anything other than a placeholder selector (e.g. %Placeholder) and don’t place any nested styles within the place holder. It seldom creates the CSS you imagine.

Don’t neglect looking at your production CSS files

From time to time, actually open the CSS file that is getting compiled (rather than merely the authoring style sheets). Run through it manually, lint it with your own version of CSS Lint (to catch what you actually care about). There are almost always unintended chunks of code. Failure to check the final product you are producing is a sure fire way to create sub-standard CSS files.

I’m spent

That’s all I got for you. As always, keen to hear your own thoughts and opinions.

Learn to use CSS effectively, 'Enduring CSS' is out now

Get $5 off HERE ↠

Write and maintain large scale modular CSS and embrace modern tooling including PostCSS, Stylelint and Gulp