Last year, Mark Otto from Github wrote a popular blog post on how they go about architecting their CSS. Inspired by this spirit of knowledge sharing, other designers and engineers have since followed suit, including:
I particularly enjoyed reading these articles as they give a warts-and-all peek into how other companies are tackling the challenges we are all facing on a day-to-day basis as front-end developers. Given the sheer volume of new technologies and methodologies appearing daily on Twitter, it is hugely useful to find out which techniques people are actually using on real code bases within projects that have all those annoying things like budgets, deadlines, and browser support requirements.
With that in mind I want to throw my hat into the ring and share how we do things on Asset Bank–our web-based digital asset management system used by organisations ranging from small local councils looking to best manage their digital assets, through to large multinationals such as Coca-Cola and Unilever.
Asset Bank is a very long-lived system, having come into existence around 10 years ago. Dig deep enough into the CSS and you’ve a good chance of uncovering some archeological relics such as IE6 fixes. That said, we have been making ongoing efforts over the last couple of years to knock the CSS (and the tooling around it) into shape.
What follows is by no means the definitive way to do CSS (we are always looking to improve), but it works for us pretty well, and hopefully you will find something useful to take away.
The first thing we did was get a preprocessor involved. We had used Sass on some other projects and loved the way it made modularity in your CSS so easy, and encouraged consistency and DRYer code with variables and mixins. A big-bang rewrite of the CSS wasn't on the cards, so we needed to cope with all the legacy CSS and provide a framework for an ongoing transition to shiny happy CSS. We opted for the following directory structure to organise our Sass files:
/base/ - contains typography styles, normalise, basic layout etc
/legacy/ - all the old CSS files were renamed as Sass partials and filed away in here
/modules/ - reusable bits of UI, e.g.buttons, dropdowns, modals etc.
/util/ - a place for mixins and utility classes
The idea is that, over time, the contents of the legacy directory will dwindle and the modules directory will grow. All of the Sass files compile down to a single main.css with minified output, which gives us a nice reduction in http requests and page weight.
At the moment, the compiled CSS file is added to Git, with the reasoning that back-end developers don't need to touch any of the Grunt/Sass stuff if they don’t want to, and it saves a step in the already lengthy building-an-Asset-Bank-release process.
In hindsight, this hasn’t really worked that well.
We do all of our work in Git branches and, with the Sass being compiled down to a single-line CSS file, you have a guaranteed merge conflict if both branches have touched the CSS in any way. Our current solution is to have a little script that developers can run to regenerate the CSS file and do the necessary git remove and git add commands. Not perfect, but it seems to be keeping everyone happy for now.
We opted for the libSass flavour of Sass via grunt-sass, because it’s faster and we didn’t want the Ruby dependency of the original Sass in a Java project. At the time, libSass was missing proper support for the @extend feature of Sass, but we figured we could live without that for the time being (support has since been added). We’ve also configured source maps to be generated, but have noticed some ongoing flakiness with them, and found them less crucial than we originally thought.
Another bit of tooling we added a while ago was grunt-autoprefixer. If you’re not already using this, then I urge you to look into it. It doesn’t take long to set up and once done your team never have to think about vendor-specific prefixes when writing CSS again (goodbye css3please.com).
We use grunt-contrib-CSSlint to lint compiled CSS rather than linting the source scss files (this is because there is no libSass compatible tool to lint scss files - hopefully one is on the way). Obviously linting legacy CSS code generates too many errors to be useful, so we set up two levels of linting by generating two separate CSS files specifically for linting:
We’re still playing around with the configuration of both linting jobs, trying to strike a pragmatic balance between encouraging code quality but avoiding dogma.
Our Grunt setup is very simple, we have a grunt watch command that listens to any changes in scss files or js files. If a scss file changes, then it compiles the CSS and runs autoprefixer against it. This currently takes around 1.6 seconds on a macbook pro, which is quick enough to not be annoying during development.
We don’t run the the CSS linting on every save, as it would slow things down too much. There is a separate grunt lint command that runs both the CSS and js linting.
Minification and concatenation of other front end assets is handled outside of Grunt by a Java-based tool called JAWR.
I was lucky enough to attend a SMACSS workshop with Jonathan Snook a few years ago which switched us on to thinking about CSS in a more modular way. We have since established a simple BEM-style naming convention that we insist on using for all new CSS in Asset Bank:
|.module-name||Aim for one word, but if it needs to be longer, separate words with a single hyphen. E.g. |
Like most people we started off loving nesting in Sass; we’re now learning its downfalls, as it results in higher specificity than you really need. The way we write CSS is something we are looking to improve all the time, and get a lot of value out of reading stuff from the likes of @csswizadry and @necolas.
We have some rules about our CSS coding style written down:
In a system developed over many years by many different people, there are lots of refactoring opportunities in the code. One thing I want to look at is ways to encourage us to get stuck into that technical debt and continue converting the legacy CSS into shiny new CSS. I was inspired by hearing in some recent conference talks that at Github they track various metrics on their CSS over time. Along similar lines, I am currently looking at using tools such as parker to track things like the number of IDs, number of !important statements and total specificity over time. That way we will have a set of graphs, visible to everyone, that we can get moving in the right direction.
Occasionally, as is the case with The National Archives, we get to work with clients across both sides of our business. In addition to custom web software development, Bright Interactive is also the company behind Asset Bank, industry leading Digital A...Continue reading... Dec. 16, 2015
Each of the speakers present demonstrated a real love for type, each brought their own case studies and demonstrations of effective uses of type on the web or in print. Here are just some samples of the useful and interesting things I picked up on from...Continue reading... Nov. 16, 2015
Last year, Mark Otto from Github wrote a popular blog post on how they go about architecting their CSS. Inspired by this spirit of knowledge sharing, other designers and engineers have since followed suit, including Mark Aparicio at Groupon, Brian Lovi...Continue reading... Nov. 5, 2015
Early one morning over the summer I joined an Institute of Directors roundtable discussion in London. These are my thoughts on exit strategies, self-managed teams and how to eat breakfast while being filmed (best advice: don't!)Continue reading... Oct. 19, 2015