Chapter 3. Implementing perceived wisdom

You often don't really understand the problem until after the first time you implement a solution - The Cathedral and the Bazaar

In the last chapter we considered some of the more obvious difficulties of dealing with a large CSS codebase. In this chapter, we'll consider some existing approaches for dealing with those problems.

Over the course of two years I've been on a CSS architecture and maintenance odyssey. Near the beginning of the experience I did what any sensible developer should do. I looked to see how smart people had dealt with the problem already.

At the time, the principle approaches for dealing with CSS at scale were:

Now, I'll tell you unashamedly right now, I've stolen elements from each. However, none of those actually solved the problems I had.

Before we get to ECSS proper I'd like to briefly go over the advantages and disadvantages of each of the existing approaches I looked at. That way, at least when we get to ECSS you can appreciate the problems it is solving.

On OOCSS

The most widely practised, and certainly most widely lauded of the existing approaches I looked at was OOCSS. That was the first approach that I utilised when trying to wrestle my ever growing CSS codebase.

One of the principal arguments for an OOCSS approach is that it removes duplication of code and therefore results in a more maintainable CSS codebase. In essence, you build a set of CSS 'Lego' pieces you can then use in your HTML/templates to quickly build out designs. The hope is that once your OOCSS styles are written they shouldn't grow (much). You re-use where possible and extend where needed.

Before we look at OOCSS I need to get some caveats out there.

  1. This isn't an attack on OOCSS, Atomic CSS or any related single responsibility principle (SRP) approaches. It's merely my argument that a different approach, depending upon your goals can offer a preferential outcome.
  2. I'm not suggesting that the approach I advocate is a panacea to all CSS scaling problems. It is not (there are none).

Responsive web design, the Achilles heel of OOCSS

For me, the two biggest problems with an OOCSS approach are:

Let's see if I can demonstrate why I feel these two issues are worth considering.

Responsive issues

I consider Atomic CSS (not to be confused with Atomic Design) to represent OOCSS taken the the nth-degree. Let's consider an imaginary Atomic CSS example:

<div class="blk m-10 fr">Here I am</div>

In this OOCSS/Atomic CSS example, the visual needs of the element have been split up/abstracted into re-usable classes. One sets a block formatting context (.blk), another sets some margin (.m-10) and finally one provides a floating mechanism for the element (.fr). Un-opinionated and terse for sure.

However, what happens when the viewport changes and we don't want 10px margin or the item floating?

We could of course make some classes to do things at certain breakpoints. For example, Mplus-cc2 might change a colour at an 'Mplus' breakpoint (Mplus here would be 'Medium' size viewports and above). But I found this practice to be slow and laborious. Making very specific changes at certain breakpoints and tying them to a class that has to be added to the HTML seems needlessly complex. Furthermore, you inevitably end up with a raft of SRP classes in your style sheets that are obsolete. What's the authoring mechanism for removing any cruft from the authoring styles sheets when no longer needed?

Maintenance and iteration

Let's continue with our prior example. Suppose at some point in the future, we change our product to a more progressive layout mechanism; we move from float based layouts to Flexbox based layouts. At this point, we will now have twice the maintenance burden. We will need to not only change classes in the markup/templates but also alter the CSS rules themselves (or write entirely new ones). Furthermore, using float is redundant with Flexbox so either we leave .fr alone (and so it continues to exist, needlessly in our CSS) or we make .fr responsible for something else such as justify-content: flex-end. But then what happens if we change the flex-direction of our parent at a particular viewport? Arrgggghhhh!

Hopefully you can see the inherent shortcomings of an OOCSS approach for maintenance when your designs change frequently or you need to render an entirely different layout at a different viewport?

A pure OOCSS example

It would be fair to argue that using Atomic CSS as an example is unfair, and perhaps doesn't fairly represent OOCSS. However, trying to get a canonical example of OOCSS is difficult as there seems to be so much disparity between what CSS authors believe it is, and how it is implemented.

I'll therefore provide some further, OOCSS only, examples. I'm going to use Nicole Sullivan's original examples from her slides 'Our best practices are killing us'.

I was reluctant to do this as Nicole's original examples are now very old (2009, before Responsive Web Design was even a thing) and, without wishing to speak for her, I dare say she might use a different example and approach today.

However, hopefully we can agree that the essential aims of OOCSS are separation of structure from skin, and separating content from container? Assuming we are in agreement on that, it is my conviction that OOCSS is detrimental to speed of creation and codebase maintainability in certain circumstances.

In a responsive web design, there are times where the structure is the skin. Or rather, the structure does different things in different contexts, and there is no sane way to handle this with OOCSS. You however will be the judge.

Consider this OOCSS example. First the markup:

<div class="media attribution">
    <a href="#" class="img">
        <img src="mini.jpg" alt="Stubbornella" />
    </a>
    <div class="bd">@Stubbornella 14 minutes ago</div>
</div>

Now the CSS (note, I have removed some OldIE specific property/values here):

.media { overflow: hidden; margin: 10px; }
.media .img { float: left; margin-right: 10px; }
.media .img img { display: block; }
.media .imgExt { float: right; margin-left: 10px; }

The 'el clasico' example of OOCSS; the 'Media object' pattern

However, maybe this media object needs to be laid out differently at a 300px wide viewport. You could set a media query to make it a column based layout in that situation. But let's say you have the same 'object' in a different context at the same viewport width? And in that context, it shouldn't be in a column layout. To surmise:

  1. One media object needs to be a column based layout at 300px wide (let's call this 'media1')
  2. A second media object needs to be a row based layout at 300px wide (as it is within another context/container, we will call this 'media2')

Let's make a class that separates more concerns. It makes a media object a column layout at a certain viewport:

@media (min-width: 18.75rem) {
    .media-vp-small {
        /* Styles */
    }
}

That gets added to any element that needs to be a column at that viewport ('media1') so you'll need to head over to the templates/HTML to make that change, adding the class where needed.

Furthermore, 'media2' needs to have a different background colour at a larger viewport. Let's add another class to separate that concern:

@media (min-width: 60rem) {
    .draw-focus {
        /* Styles */
    }
}

Head into the HTML/template to add that style where needed.

Oh, and 'media1' needs the .img to be wider at the larger viewport and not have the margin. We can make another class for that:

@media (min-width: 60rem) {
    .expand-img {
        width: 40%;
        margin-right: 0!important;
    }
}

Back into the HTML/templates to make that change happen.

Hopefully now, you can see where this is headed? There's a lot of Single Responsibility Principle (SRP) classes being added to facilitate the many and varied scenarios our media object needs to facilitate.

This approach was not making my large responsive code base more maintainable. In fact, quite the opposite. Whenever changes were needed it was necessary to go hunting for the particular SRP class for the specific situation and often add/remove HTML classes in the markup/templates too. Which made me ponder the question:

Why can't the thing, just be the thing?

For now, you may counter with, 'this is a daft example, if a design has so many eventualities, it should be normalised'. At which point I would counter that it shouldn't be necessary to. Those tasked with coding the front-end shouldn't need to hobble a designers creativity just because it makes their code less predictable. They should be able to code out a new design simply and easily without concerning themselves about how the new component/module/thing may impact others.

When I've used OOCSS to tackle my needs, my speed to build new visuals decreased and the amount of single responsibility principle classes increased; often a class is used just once or twice on an entire project.

When using OOCSS on a rapidly changing project I also found that after some time, I found it incredibly frustrating to 'unpick' these abstract classes when changes were needed. I was having to make many very similar abstract classes when they were seldom actually used. Utility classes like w10, w15, w20, w25 etc for different width percentages seemed like a good idea and an obvious abstraction to make but they ultimately proved useless and problematic to iterate designs with (back to the problem of things needing to do different things in different contexts).

My first big lesson when employing OOCSS therefore was the same lesson that the fine fellow Kaelig Deloumeau-Prigent learnt in his time working on large CSS codebases at the BBC and The Guardian newspaper:

Two years ago I wrote a book where I was preaching DRY code, but after working on enduring projects, it's "decoupling" that became more important to me.

On large, rapidly changing projects, being able to easily decouple visual modules from the project is incredibly important for ongoing maintenance and OOCSS didn't facilitate this need well.

SMACSS

SMACSS, which stands for Scalable Modular Architecture for CSS, is detailed fully in Jonathan Snook's book on the subject. I'm not going into detail about SMACSS here as I think you should go and check that book out for yourself. Reading SMACSS gave me plenty to chew over as I faced my own challenges and I certainly took things, such as how to think about state changes, from it. However, I will detail why SMACSS didn't work for me. Again, like my caveat regarding my opinions on OOCSS, this isn't a critique of SMACSS. It's simply highlighting the parts that didn't work for me and why I felt it failed to solve my own problems. SMACSS has clearly defined terminology and concepts for the visual aspects of a website. It therefore prescribes base, layout, modules and optional theme rules/files to support these definitions. For example, consider this suggested file structure:

+-layout/
| +-grid.scss
| +-alternate.scss
+-module/
| +-callout.scss
| +-bookmarks.scss
| +-btn.scss
| +-btn-compose.scss
+-base.scss
+-states.scss
+-site-settings.scss
+-mixins.scss”

Excerpt From: Jonathan Snook. “Scalable and Modular Architecture for CSS.”

While these definitions make perfect sense in many scenarios, they didn't for mine. I wanted an approach that was looser, an approach that didn't make me need to consider fitting what I needed to build into those visual definitions; the applications I was building and maintaining often defied adherence to those definitions.

BEM

BEM is a methodology developed by the developers at http://yandex.ru.

The key thing I took from BEM (which stands for Block Element Modifier) is just how much a naming convention can buy you when it comes to CSS maintenance.

Again, like SMACSS I'm not going to attempt to fully explain the ins and outs of BEM methodology. However, I will give you the 'elevator pitch' explanation of the key points. The BEM methodology works around the notion that key areas of a page can be defined as 'Blocks'. In turn, those key areas are made up of Elements. We can then represent the relationship between the Block and its Elements in the way we name things. Consider the OOCSS media object example from before. In a BEM approach we might use classes like this:

<div class="media">
    <a href="#" class="media__img">
        <img class="media__headshot" src="mini.jpg" alt="Stubbornella" />
    </a>
    <div class="media__attribution">@Stubbornella 14 minutes ago</div>
</div>

What's so useful about this naming scheme is that it clearly communicates a relationship between the elements and the block they belong to. Plus, away from the HTML, if we came across a selector like this in the CSS:

.media__headshot {

}

We instantly know that this is a Element called 'headshot' that lives inside a Block called 'media'. This namespacing a component as part of something else helps to isolate styles and prevent the applied styles from 'leaking' out – one of my major bug-bears with OOCSS. This was definitely a step in the right direction for the problems I was trying to solve.

BEM also has the notion of 'modifiers'. A modifier is something that gets added to the Block to modify its appearance. Suppose we wanted to theme our media object differently in a different scenario. BEM facilitates it like this:

<div class="media media_dark">
    <a href="#" class="media__img">
        <img class="media__headshot" src="mini.jpg" alt="Stubbornella" />
    </a>
    <div class="media__attribution">@Stubbornella 14 minutes ago</div>
</div>

The BEM documents dictate the use of a single underscore character to identify a Modifier for a Block. This modifier class must always be used alongside the block name. For example, you must do this:

<div class="media media_dark">

And not this:

<div class="media_dark">

I see the value in using modifiers in this manner but it proved problematic for me. Often the things I was styling needed to behave differently in a more traditional manner. Perhaps visuals needed to display differently depending upon the context they were being used, or if another class was being added above it in the DOM. Or due to certain media query conditions, or indeed any combination of those scenarios. I needed a way to author styles that was pragmatic enough to deal with the non-ideal situations that occurred. Some way to keep some sanity in the authoring style sheets no matter what was thrown at them.

Summary

Of all the existing CSS methodologies I looked at, I took the most from BEM. There is much to appreciate in BEM:

However, the use of modifiers didn't really fit my needs. Although perhaps it wasn't preferable, my reality was that often I would need to override styles on a Block (in BEM parlance) depending upon some eventuality above it or by the side of it in the DOM.

For example, in the scenario where existing logic is already determined in an application, there may be a scenario where a class like contains2columns would be added above the item in question in the DOM and I would need to style changes based upon that, as opposed to changes directly upon the Block in question.

With BEM I couldn't find a clear way of understanding how that eventuality should be handled. Or how I could contain those kinds of overrides in the authoring style sheets. I wanted to define items and encapsulate all the eventualities that may occur on a particular item.

I also found the syntax confusing to reason over when glancing at classes. The differentiation between the way modifiers were written and the way elements were written was negligible. This would be an easy fix but it was still something that bugged me about it.

Finally, I realised I needed something extra. I wanted the ability to communicate and facilitate different contexts for a module. When a 'thing' was created by the same piece of logic but could be used and styled differently in different contexts, I wanted a means of communicating that.

From SMACSS the main thing I found useful was dealing with state. I liked the declarative manner in which classes like is-pressed or attributes .btn[data-state=pressed] clearly communicated the state of elements.

OOCSS turned out to be the antithesis of what I needed. Whilst I appreciate what OOCSS can offer, it wasn't the solution to the problems I had. I didn't want to create a Lego box of styles that authors could use to build up visuals in a DOM/template. The abstractions OOCSS facilitated were inherently 'leaky' which made maintenance problematic (change the value in one rule and you may inadvertently effect many elements), it was also difficult to find ways of dealing with varying viewports, for all the reasons already explained.

Ultimately, by trying and failing, to varying degrees, with each of these existing solutions I finally fully understood my problems. Now it was time to tailor a bespoke solution. To paraphrase Pablo Picasso:

Good coders copy, great coders steal
Pablo Picasso (sort of - sorry Pablo)

Walk with me.