Introduction – Why Do We Even Care?
Let’s start our discussion with a funny gif. I blieve it sums up the purpose of this blog post pretty well.
CSS is very powerful. It’s what gives us the pretty web. But unfortunately, like a lot of other powerful technologies, it can be easily abused. When it is written badly, the severity of the consequence can range from confusing code to next-to-impossibe maintenance or modification of software.
The Big Problem With Badly Written CSS
From my personal experience, when it comes to potential problems with CSS code, the big elephant in the room is maintainability. We can describe this problem in several ways. One way to describe it is that when CSS is written poorly, it’s very easy and likely to break things when making a change. This in turn can cause all kinds of problems: it slows down product development and innovation, it strips away developer’s confidence, it encourages more bad CSS code, and worst of all, sometimes you don’t even know some UIs are broken until the user finds out. That’s not good, in case you are wondering, esp. when it’s the UI that’s broken.
Here’s an example of the power of CSS and the danger of bad CSS code:
In this example, we are able to specifically style the <span> inside any <p> nodes with a class of “.product-desc” inside any <div> nodes inside the node with an ID of “mainContainer”. Pretty cool and powerful stuff, right? Well, not so quick.
What if later on we decide to rename our “mainContainer” div to something like “main”? You may say, “Well, you could, but that doesn’t happen very often.” Ok, fair enough. What if we decide to put all the “p.product-desc” nodes into <section> or <article> nodes instead of <div> nodes? Also, what if we decide to use a different CSS class names for <p>, say “product-description” instead of “product-desc”? What if the <span> nodes get moved outside of <p> nodes? The “what if” scenarios can go on and on. Anytime you make any of those changes, your UI would be broken. That’s pretty fragile UI code, and that’s NOT what you want.
What you REALLY want is having the confidence to come back later and make UI changes without worrying about breaking other UI components. Let’s talk about this in a little more detail.
A side note: this is a great example of CSS code with high specificity. What we want for large projects is CSS code with low specificity. To understand why that is and what CSS specificity is, read this article.
What We Really Want – Goals and Desires When Writing CSS For A Large Project
I want to mention really quickly here that this blog post is more targeted towards LARGE web projects with lots of CSS code. What I mean by “large”? Well, if you end up with hundreds, or even thousands, of lines of CSS code, then you should consider it a large project, as least from the UI perspective. For a large project, you have to have some kind of methodology for writing your CSS code, otherwise you are just begging for weeping and gnashing of teeth for ongoing maintenance. If your project is fairly small, meaning you only have a few pages and you end up with less than a couple hundred lines of CSS code, or fewer, then you can get away with bad CSS code. However, I recommend you using this guide for projects of any size because it will benefit even a smaller UI project, and I believe this guide will serve you and your team well.
So, what do we really want when writing CSS for a large project? Below I’ve made a list of what was important to me and my teammate (Ravish):
- We wanted to receive precise and easy-to-understand UI specs from our business and UX teams, which we did. If you are interested in learning more about how to define UI specs to developers, I’ve written another blog post for that.
- We needed a consistent way to write CSS for the team so that our CSS coding style looks similar and we could easily understand each other’s code.
- We needed a way to write the CSS without many file merge conflicts between team members.
- We wanted to take advantage of the benefits of a preprocessor such as variables, mixins, etc. We ended up using LESS.
- Most importantly, we wanted to write the CSS in a way that gives us confidence to come back later and change something without worrying about breaking things. This meant faster iteration, and better sleep at night. 🙂
Based on these goals and desires, I started looking for a good solution. I found lots of resources on this topic. Eventually I decided I really liked what I saw from the Trello CSS Guide due to its simplicity and comprehensiveness, and realized there’s really no need to reinvent the wheel. I recommended it to my team and we all liked it a lot. So we ended up adopting the Trello CSS Guide for our projects. Later on in this blog post I will give you the major highlights from the Trello CSS Guide, and then tell you about how we put it into practice with our project.
But before that, let’s talk about the PROCESS we go through before we write the first line of CSS, because there’s a lot that goes on before that point.
Process Matters – Converting Specs to Actual UIs
A lot has to happen first before developers start writing code, and the same applies for CSS code. From my personal experience, I know a lot of software projects can end up looking really crappy, or even unusable due to poor UI/UX. This can happen due to many reasons, one of which could be that developers starting to write UI code without getting good UI specs first, or not having a good understanding of business requirements. This process can not and should not be rushed because it dictates the quality of the software even before the construction starts. When you put in junk, you will get junk back. It’s that simple.
So that begs the question: what does a good process look like? In my opinion, the process should look somewhat like the following:
- Assuming Product Owner (or business team) has good requirements defined already, they will work with UX team to create the UI specs.
- Once they reach the first draft of the UI specs, PO and UX team will walk through the new UI specs with devs to weed out obvious issues.
- The devs then will work on completely understanding the specs, give feedback, and even push back on some specs if necessary.
- Once everyone is happy with the specs, the dev team will need to divide up the work and start working. Dividing up the work can be tricky and can depend on the team you have. We divided up the work based on the rule that if one dev is working on a UI, then any other UI that’s similar will end up getting assigned to that dev too, assuming it doesn’t significantly increase the dev’s workload. This rule worked pretty well for us, granted we were only a team of two.
- At this point, the devs have their marching orders and they can get to work. They will decide how they want to structure their project to optimize code organization, team collaboration, source control and ongoing maintenance.
This is a somewhat oversimplified version of what the process looks like, but I believe it captures the essence of what a team will need to go through in order to figure out WHAT UIs they are trying to construct.
Adopting A CSS Guide – The Trello CSS Guide
I’ve done quite a bit of research about best practices for writing CSS for large projects. There are many options out there, including the well-known BEM pattern. After a while, I realized that the important thing is not to try to figure out the best one, but find one you like and one you think that’s good enough, and stick with it. For us, we really liked what we saw from Trello’s CSS Guide.
Because this blog post is not about repeating all the details of the Trello CSS Guide, I will only mention the highlights here. Please take some time to read it for yourself as it is very well written. As described in this blog post, the BIG TAKEAWAYS are quoted here below. The main thing you will notice from this CSS guide is that they only use CSS classes for selectors. The main reason for this is that it will always guarantee low CSS specificity, which is exactly what we want.
Trello CSS Guide – The Big Takeaways
I tried my best to explain each of the sections and the rationale behind them. The key idea is at the top of each section. Important ideas are highlighted. There is elaboration. I like to think it’s pretty scannable and readable. But if you’re in a rush, like maybe you need to respond to some emails, here are the big takeaways:
- Be leery of preprocessor features. Use only imports, variables, and mixins.
- Use the
- Use the
.component-descendant.mod-modifierpattern for modifier classes. No bare
- Use the
.component-descendant.is-statepattern for state. Manipulate
- Don’t use global media queries. Include media query variables in your component.
- Separate presentation and behavior concerns by using
- Prefix mixins with
.m-and only use them for browser polyfills.
- Prefix utility classes with
- Use lots of components and files.
- Use normalize.css.
- No ids, element, or universal selectors. Use kebob-cased classes.
- Use a consistent style.
How We Put The Trello CSS Guide Into Practice
Once you have a good understanding of the Trello CSS Guide, you will realize that you need to think about your UI in terms of components. That’s your starting point. I thought this was a great idea because decomposing the UIs into components is the most natural way to think about UIs, and it gives us a great way to write low specificity CSS classes. Let me demonstrate with an example from our project. Note that this approach works for both desktop and mobile versions of the UI, so it is very much compatible with responsive design principles.
One of our sites’ login page looks like this in the desktop view as defined by UI specs:
When you spend some time decomposing this UI into components, it’s really not hard to come up with something like the following:
The HTML looks like this:
The CSS looks like this:
I think it’s pretty obvious to see how we put the “component-descendent-descendent” pattern into practice here. There’s one and only one CSS class in here that didn’t follow this pattern. Do you see it? That’s right. It’s the “sign in” button. Here we actually created a class called “agx-btn-orange” because it is a button style that’s shared with other UIs in our project, and this class is put into a separate (LESS) file that’s dedicated for shared button styles. In this file there are a few more button styles, such as “agx-btn-gray”. For the “sign in” button, we also created a modifier class “agx-btn-orange.mod-small” because this particular orange button is a little smaller than the regular orange buttons used throughout the project. Note that this class is not “mod-small”, but “agx-btn-orange.mod-small” because we don’t want bare modifier classes. Modifier classes should only be defined with the component class it’s trying to modify.
I’d like to point out here that, as you can see, the class names can get pretty long. So, if you have a lot of nested UI components, then you will have to be a little creative with naming, maybe use some abbreviations or other clever names. But personally, I’d rather have a long but descriptive class name than something that’s hard to decipher. You decide where the balance is with your team.
Reaping The Fruits of Our Labor – The Benefits of Using Trello CSS Guide
Before we were done with our project, we knew using something like the Trello CSS Guide would give us the following benefits:
- It gave us a plan and a reference – a good plan I might add – rather than every developer ad-hocing on their own.
- It gave us a method to decompose each UI into smaller components and write the CSS for each component.
- The Trello CSS guide didn’t suggest us doing anything fancy with LESS (only imports, variables and mixins) so our CSS is fairly easy to understand. This is nice for ongoing maintenance and fresh eyes.
- Now, the big one: When we were done with our sprint, and pushed the changes to our QA environment, we received feedback from business folks who wanted to make a few minor changes. We had so much confidence in ourselves that making those changes was NOT going to break other UIs. That was a great feeling. Not only that, we were able to quickly pinpoint which classes needed to be changed, and we changed them pretty quickly. This resulted in a very fast turnaround time, which means everyone is happy, and developers can sleep better at night. 🙂
- We used Bootstrap for responsive design.
- We assumed mobile first and used media queries to apply styles for larger screens. This was partly because Bootstrap also uses a mobile first approach.
- We applied “box-sizing: border-box” style to all of our html elements because we thought “border-box” made it easier for us to control the sizing. Read this page to see how to apply “box-sizing: border-box” to your entire project.
I hope you find this blog post helpful for your future projects.