During the last few years I have found myself dealing with largish codebases on various projects. During that time I have continued to assess the tools and techniques used to make it as easy as possible. This post explores ways to make developing on large CSS codebases more enjoyable.
CSS is sometimes described as a simple and easy language. I tend to agree but it’s hard to master. It can quickly become very complex and working with it can be a pain if there is no structure.
As projects evolve, so does CSS. More often than not, code is just added to “fix” or “update” a bug or feature. Before you know it, the CSS is a complete mess and is scary to modify, is unmaintainable and resembles spaghetti.
Thankfully this can be easily avoided if there is some structure and guidelines around the code.
Keep things simple
It’s easy to get carried away, but I feel this is the most important rule to try and keep in mind.
This tip does not just apply to the code, but also to the build tools, processes and folder structure. Aim for the “simple” solution at every possible opportunity.
When it comes to CSS keeping things modular and focusing on the single responsibility principle helps with the maintainability and cleanness of the codebase.
In object-oriented programming, the single responsibility principle states that every context should have a single responsibility and that responsibility should be entirely encapsulated by the context. All its services should be narrowly aligned with that responsibility.
Each module should aim to do one thing and be encapsulated. This means that the CSS for a module doesn’t care about another module whilst being flexible, meaning it can be used in any context and not effect other modules.
Use a pre-process but don’t go crazy
During the last few years developers writing CSS have jumped all over pre-processes. For good reason. But saying that, they can also be harmful if used incorrectly.
Being conscious of the CSS output is key. Just because you have the power of functions, mixins, variables, etc., use with caution. There is no need to introduce complexity into your authoring if there is no benefit. Simple is good.
Also, at the end of the day, it doesn’t matter which pre-processing language you decide to use, just make sure everyone on your team is happy with the decision and take the time to learn how to really utilise it.
Have some coding standards
You don’t necessarily have to produce documents describing what you will and won’t do. Just agree on some general conventions that your team are in favour of and stick to them.
Utilising what others have done, like Idiomatic CSS, is a great starting point that I would highly recommend if you have no idea where to begin.
Naming conventions
I couldn’t recommend taking the time to adopt a naming structure like BEM enough. It helps keep structure to modules and maintenance becomes less of a pain.
If you are keen to dive into BEM, Harry Roberts has you covered – Getting your head ’round BEM syntax.
There are variations of the BEM syntax which are also worth looking into. One that I would recommend is the Suit CSS convention
One argument for not going down the BEM path is it’s a poor choice for migrating. Nicolas Gallagher explains.
Classes or ID’s
This is a little bit of a hot topic and really deserves a full article but once going down the “only” classes road, you probably won’t look back.
Using ID’s with a large codebase quickly introduces specificity headaches which can quickly escalate out of control. I would highly recommend this article if you are undecided.
Even though this article focuses on CSS, JavaScript is part of nearly every website these days and one thing I have found to be extremely helpful is decoupling JavaScript classes from the CSS using a “JS” prefix.
<a class="js-menu-toggle btn btn--large">
...
</a>
Doing this provides a clear distinction on what the class does and really is only in the markup to be hooked into from JavaScript.
Having JS prefixed classes provides an easy distinction for developers that the module or component is attached to some JavaScript functionality. This means that the likelihood of anyone accidentally breaking any JavaScript is reduced drastically.
Comments
Well-commented code is extremely important. Take the time to describe components, how they work, their limitations and the way they are constructed. Don’t leave others in the team guessing as to the purpose of uncommon or non-obvious code.
– Idiomatic CSS
File structure
I feel this differs for each project but keep it simple. If you are nesting directory inside multiple directories or you are having problems finding files, reassess your structure.
This article by Hugo Giraudel is a good starting point for helping set up a base structure – Architecture for a Sass Project.
Also, learning the shortcut’s in your editor of choice to quickly look up files can be a life saver when the codebase is large (Command + P in Sublime Text).
Editor setup
Everyone has a unique way of working and setting up their environment but the aim of a large (or any really) codebase is to have the code look like it is authored by one person. Using a plugin like EditorConfig helps solve this problem. EditorConfig helps define and maintain a consistent coding style between different editors and IDEs.
A build process
Having a build process that helps and enforces some of the chosen coding standards is a game changer from my point of view. It’s one thing to agree but to actually enforce things creates a codebase that is a pleasure to work with.
Some handy build tasks to consider:
- Autoprefixer — Parse CSS and add vendor prefixes to rules by Can I Use.
- ImageOptim — Users the ImageOptim-CLI to automate optimisation of images.
- Recess — A simple and attractive code quality tool for CSS.
- Grunt CSS — Grunt plugin for linting and minifying CSS. A Gulp version can be found here.
- Grunt Sass — Compile Sass to CSS. A Gulp version can be found here.
Pro-tip – Set up Sass source maps to reduce the friction whilst developing!
Remember, at the end of the day, it doesn’t matter what build tool you use, just use one.
Also, introducing an incentive to not break the build makes developing a little more fun. For example, at a recent workplace we had the rule: “If you break the build you buy everyone coffee”. Somedays I was buying everyone coffee. Other days I was completely wired. This proved to introduce a great bond within the team, something I would highly recommend.
Lie to your boss and re-factor during development
Take the time to re-factor during the development. Don’t just wait for time after the project or feature has launched. Do what it takes to find time. You may have to lie to your boss, over estimate or skip a meeting. It’s totally worth it!
Before you know it CSS can quickly get out of control. Working with complicated files is time-consuming, painful and unnecessary.
Use Version Control
Having code in version control is a no brainer. If you can utilise services like GitHub or Bitbucket for extra functionality, it’s highly recommended. Making use of pull requests and comments for a greater depth of discussion in the development workflow can produce higher quality code. Just be sure the processes you decide on work for the team.
Test often
There is nothing worse than coming to the end of a sprint or pre-launch and realising you have loads of cross-browser bugs to fix.
Make an effort to test during development.
Focus on testing each module before committing for review. Taking the time to make sure it works across all supported browsers and devices during development eases the pain and produces a more solid codebase.
Even though we have been bombarded with a billion screen sizes to support in the last few years, the tools for testing really have advanced.
Tools that are worth checking out:
Discuss and evaluate
It’s easy to focus on shipping the product or feature but making time during development to think and talk with your team can be extremely beneficial. It doesn’t have to be a formal meeting, just grab a coffee together and shoot some ideas around. You never know what ideas you will come up with.
Being scared to change and evolve your process/rules can be harmful. Stay open-minded.
Final thoughts
Working with a large CSS codebases is hard. It can be painful and daunting but it doesn’t have to be. Taking a few precautionary measure during development can help mitigate pain and make your CSS a pleasure to work with.
Good luck!
Thanks some really good tips here!
Nice article, as for testing we generally have a wide variety of devices in the office running native browsers, but I must say im also an advocate of Browser Stack, its a nice service, a wide range of available devices, os, browsers and versions available for testing and a nice price.
My favorite part: “Lie to your boss and re-factor during development” Haha…
I personally like to just factor time for refactoring into my estimates. If you’re working with reasonable people, it’s easy to justify the time saved by continually refactoring versus the time spent on hacking spaghetti specificity nightmares.
Solid post, thanks for putting this all together!
It’s my favorite too! Hard to find a good boss…
Your first idiomatic link does not work, last ‘s’ is missing. Thanks for the article, it’s great!
Thanks Egbert. This is now fixed.
Great reading thanks!