Rethinking CSS

If your answer to any of these questions is yes then this is an article for you.
Working on a monolithic code base with CSS bloat?
Having to deal with convoluted CSS?
Having a specificity war in CSS?
Using !important is your solution in CSS?
Yes, we faced all these issues working on a code base that suffered from a lack of standardizations for years. It was a challenge to work with the current CSS structure as new code was constantly being added on top of older code. A CSS bankruptcy was declared as it became difficult to work with the existing structure in place without adding more to the mess. It was about time we stop adding to this bloat and find a solution to this ever-growing problem. As new developers on-boarded they faced similar difficulties and had no clear path.
Having to work with this bloat also slowed down the speed at which developers could be developing new features for our customers. It became a challenge for us to solve this problem and define a path forward for everyone.
Where did we start?
This is first thing that comes to mind and is the critical step in solving any problem.
At an early stage, we tried to solve for higher-level CSS problems like, how we can make it easier to write CSS?, how can we write clean CSS? etc. We quickly realized this was not the correct approach to such a large problem with many moving pieces.
We learned that we needed to track down and target the core problems.
Finding the core problems took form, as questions that we had to take time to examine:
What are the problems developers face while writing CSS?
What overarching themes can we find that tie these problems together?
Can these problems be defined as architectural issues?
What potential ways would we work around those problems?
These turned out to be the key questions towards arriving at a solid solution.
How did we approach the problem?
Once we had detailed the core of our CSS problems, we invited all developers to a Guild style meeting for an open discussion on the problems and their potential solutions.
Here are couple core problems listed we addressed.
No defined meaningful naming convention for CSS classes
Lack of standards around meaningful naming conventions for writing CSS classes is a small problem but over the time this can pile up to create even larger problems.
Problems:
- No Naming standard
- No meaningful class names
- Lots of leftover CSS when features are removed
Ideas:
- Snake casing OR Lowercase and hyphen separated
.someCssClassName // Snake case
.some-css-classnameThese two approaches provided only a naming standard but still doesn’t solve the problem of increasing complexity of specificity and clear meaning with the naming convention.
- BEM (Block Element Modifier)
.some-block
.some-block__element
.some-block__element--modifierBEM captures the purpose and meaning of CSS through its classname syntax. It also touches some well-known object-oriented programming principles of DRY and SOLID.
BEM provides a single class name pattern, which has the benefit of having better performance. Since, rendering engines evaluate CSS selectors right to left there is less to evaluate, hence it renders faster.
It also makes it easier to remove CSS as when we remove features, since we can easily relate blocks of HTML to its equivalent CSS classes.
Read more about BEM here.
Due to all of its benefits BEM was a clear winner.
Specificity Wars
If you have ever had to fix a nasty styling bug caused by an ID selector or unhealthy amounts of nesting, my heartfelt sympathy goes to you.
Problems:
- At times, we saw 7–8 levels of CSS specificity applied to certain sections of the page, as well as the use of overrides that were added as a `quick solution`. These things caused slow rendering in the browser.
- Lots of duplication of styles.
- Too many rules resulted in long compile time for generating source maps.
- CSS selectors affected unwanted areas of code.
Ideas:
We evaluated the following approaches.
SMACSS is a way to check your design process and as a way to fit rigid frameworks into a flexible thought process.
At the very core of SMACSS is categorization. By categorizing CSS rules, we begin to see patterns and can define better practices around each of these patterns.
There are five types of categories:
- Base
- Layout
- Module
- State
- Theme
SMACSS approach gives a solid structure for laying out CSS and categorizing them. It makes it easier to know where the CSS for a given class is to be found. This approach works well with BEM pattern as well.
The usage in HTML and CSS looks like this.
// HTML<div class="l-container">
<span class="badge is-badge-primary">1</span>
<span class="badge is-badge-secondary">1</span>
</div>// CSS.l-container {
padding: 10px;
border: 1px solid #777;
}.badge.is-badge-primary {
background-color: #d45d00;
color: #fff;
}.badge.is-badge-secondary {
background-color: #63666a;
color: #fff;
}.badge.is-badge-tertiary {
background-color: #ebedef;
color: #63666a;
}.badge {
display: inline-block;
min-width: 10px;
padding: 3px 7px;
font-size: 12px;
font-weight: 700;
line-height: 1;
text-align: center;
white-space: nowrap;
vertical-align: middle;
background-color: #777;
color: #fff;
border-radius: 10px;
margin-left: 10px;
}
Read more about SMACSS here.
- ITCSS (Inverted Triangle CSS)

Much like SMACSS, Inverted Triangle CSS helps you organize your project’s CSS files in a more consistent and manageable way. It helps you manage CSS specifics like global namespace, cascade, and selector specificity.
To do this, it separates your CSS code base into several layers which take the form of an inverted triangle as depicted in the picture.
ITCSS has three key metrics
- Generic to explicit
- Low specificity to high specificity
- Far-reaching to localized.
Read more about ITCSS here.
Even though SMACSS and ITCSS solve more of the architectural problems, they are still just basic guidelines. We’re still left with questions and certain topics that are up for interpretation. In fact, some aspects of the architecture may not even apply to your project.
Adopting either of these would solve some of our problems, but it would be difficult to enforce these standards, and monitor all the changes being made to make sure they align with these principles.
- OOCSS (Object Oriented CSS)
OOCSS is an approach for writing CSS that’s fast, maintainable and standards-based.
OOCSS proposes two main principles
- Separate structure and skin — Define repeating visual features as separate skins that you can mix and match with various other objects to achieve a variety without much code.
- Separate container and content — Do not use location dependent styles. An object should look the same no matter where you put it.

Read more about OOCSS here.
The concept of OOCSS is pretty straightforward, embodied by the creation of generic classes that are reused as much as possible. This is achievable when we have classes with single responsibility. This approach is unique but familiar concept for everyone with a programming background.
OOCSS solves the core problem of specificity. It promotes highly reusable classes, which reduce duplicate, or even conflicting, CSS. These less complicated CSS rules make the code easier to understand and also has better render performance. For these reasons, this approach looked very promising to us.
Soon after we did more research on using this approach, a couple colleagues introduced us to Tachyons.
Tachyons turned out to be the best implementation of OOCSS. It provides with a lightweight library of classes that are highly modular, reusable, performant and readable.
Quick example of a component using tachyons looks like this:
// Primary badge<span class="dib ph2 pv1 f7 fw7 lh-solid tc truncate v-mid bg-black-60 white-90 br-pill ml3 sans-serif bg-orange white">1</span>// Secondary badge<span class="dib ph2 pv1 f7 fw7 lh-solid tc truncate v-mid bg-black-60 white-90 br-pill ml3 sans-serif bg-gray white">1</span>
Tachyons encourages 100% responsive design and a mobile first approach. It encouraged developers to reuse classes, which reduced the amount of CSS needed to little or none. In honesty, when I first saw this library, I was hesitant to use it. My colleague urged me to at least give it a try, and, by the time I wrote a couple modules using Tachyons, I fell in love with it immediately.
Using tachyons not only helped us solve the bulk of our CSS problems, but also insured us against running into those same problems again in the future.
Read more about Tachyons here.
In addition to addressing the core problems, we incorporated a few other standards and practices that worked well with this approach:
- Not using ID selectors in CSS
- Ideally, there will be very few cases where we need to write actual CSS, when we do write CSS make sure they follow OOCSS pattern.
- Adding sufficient documentation for the added CSS.
- Set a standard for margins on a component and let the component decide what goes on top and left of itself.
- Use Flexbox classes provided by tachyons for grid layout.
- Being 100% responsive and mobile-first approach.
Conclusion
Using the BEM pattern for naming convention and taking the OOCSS approach with Tachyons helped us solve most of our CSS problems. Unhindered by CSS tech debt, and no longer adding to the bloat, we now have a clear path forward for new development, and have increased productivity for the long-term.
If you are interested, here are some examples that we attempted as POC https://cssstandards-wtwkvwadvv.now.sh/
Kudos to the team for supporting, accepting this change and making it happen. Special Thanks to Kyle Scully and Mark Holmes for the proposal of using tachyons.
