var self = justin();

Software Developer Teammate

A place to remind my future self of what I've learned and experienced. That means both my successes and failures.


CSS Architecture

I recently watched a great talk by Anthony van der Horn over what he calls bringing SOLID into CSS and JavaScript. In the video, Anthony talks about a great method for creating maintainble CSS.

Over the past year, I've been doing a lot more work on the front end and, while my JavaScript skills have improved, my CSS skills haven't remained stagnant. I'm not talking about the skill in understanding CSS and knowing how to use it. I mean crafting maintainable CSS.

A Simple Problem

Here's a little bit of markup:
<ul class="products"> <li>Product 1 and content</li> <li>Product 2 and content</li> <li>Product 3 and content</li> </ul>

And some style to go with it:
ul.products li{ border:1px solid black; }

I've written CSS like this many times. Obviously, this finds any list item that is a child of the .products class and puts a solid, black, 1px wide border around it. So, what's wrong with this?

Let's say that we need to refactor the content to take advantage of HTML semantics and help out our SEO. So we change the markup to this:

<section class="products"> <article>Product 1 and content</article> <article>Product 2 and content</article> <article>Product 3 and content</article> </section>

Now we need to go and modify the CSS to look for articles instead of list items.

section.products article{ border:1px solid black; }

But do we have any other markup depending on that CSS? Well @#!$... who knows? Let's take care of it just in case:

section.products article, ul.products li{ border:1px solid black; }

Now we've got this ugly selector that is tied to a specific markup. How can we change this?

SOLID and CSS

Yes, I know... SOLID and CSS doesn't really make much sense. However, if you think about it in terms of how it is coupled to markup, then you can pull out some really good insights.

Open/Close Principle

Ok, when talking about object oriented programming, the open/closed principles is about writing code that is 'open' to extension and 'closed' to modification. In a nutshell, it means that you should be able to add new functionality to your code without mucking around the internals of existing code. Yeah, yeah, it's a nice philosophy and sometimes it's difficult to do, but its a good principle in general.

So how does this apply to CSS? Wouldn't it be nice if you could make some changes to your markup and still have your CSS apply the correct styling? Obviously, this isn't possible for every scenario, but how would something like that look?

I'm sure you already know how we can take the previous example and make it less coupled to a specific markup.

Here's that markup again but with a slight change:

<ul class="products"> <li class="product">Product 1 and content</li> <li class="product">Product 2 and content</li> <li class="product">Product 3 and content</li> </ul>

Now we can use the following CSS:

.products .product{ border:1px solid black; }

That CSS will work for either of the two markups we looked at above.

Layers

By now, you might be deciding whether or not to keep reading. If you've come this far, then I'll reward you with something a concept I find very cool.

In software architecture, you design specific layers and interations between the layers. You might design an architecture where code from the UI layer cannot have direct access to the Data Layer and must go through some intermediate layer.

In CSS Architecture, we can do something very similar. We can define four specific layers: Document, Base, Module, Layout.

Document

The Document layer is where you can define the defaults for your html. Things like ul, div, h1 and all the others get their styling here.

Base

The base is your first layer of reusable components. Things like buttons, modals, and inputs are done here.

Module

Module has all of the styling for your content. This is where we would define the .products and .product from earlier.

Layout

Lastly, the layout holds all of your layout specific styling. Things like sidebars, columns and grids.

Now these layers don't have to be separated by different files, though that might make it easier to keep clean. The main thing here is to not mix your selectors from different layers.

Examples

Let's go back to the earlier example of products.

Here's the first iteration of the product styling:

ul.products li{ border:1px solid black; }

Can you see a cross in the layers? li is in the base layer and .products are in the module layer.

So when we made the change to this:

.products .product{ border:1px solid black; }

When we introduced the product class, we actually pulled the base styling out of the module styling. Now this styling can be applied to many iterations of markup.

What about this one:

.sidebar .product{ border:1px solid red; }

We are using classes in both parts of the selector but .sidebar belongs to layout and .product is from module. How can we refactor this to not violate the layers of our architecture?

.side-product{ border:1px solid red; }

Here's another:

.column1 > div .feedback > button{ border-radius:3px; background-color:orange; }

Any thoughts?

Let's just rename it to:

.feedback-submit-button{ border-radius:3px; background-color:orange; }

Where's the Cascading?

Ok, you caught me. In the previous examples, the solution I chose was to pick a better name and remove much of the selector heirarchy. "But that's the point of CSS! Class inherit from other class that inherit from other classes that...."

Whoa, bro. You remember when you first started in Object Oriented Programming land? EVERYTHING WAS AN OBJECT AND ALL THE THINGS INHERITED!

Then you realized that this was unmaintainable. You often had very difficult code to debug or extend. You know that have heirarchies 7 levels deep is generally a bad thing (I'm looking at you, webforms), so why are you doing it in your CSS?

Did it just click? Because that's when it clicked for me. Instead of trying to nest all of my CSS, I could give better, more explicit names that better relayed the intent of the styling.

Pop Quiz! Can you tell me the intent of the following CSS selector? .main-content > .products li .details + button

What about this? .buy-now-button

I bet you are a compentent developer. I bet you spend time thinking about your class hierarchies and their names. You think about what the intent of the name implies and how easily it will be for others to quickly understand how to use it. You know to identify and stick logical layers in your software. You know how to work inside of an architecture.

You already know how to write good code, now let's write better CSS.

comments powered by Disqus