Are you Single?
I find it interesting when two (or more) people can say something but the way that something is interpreted can be quite different.
Nearly four years ago, Harry Roberts wrote about applying the single responsibility principle to CSS.
Within the article, Harry explains how defining too many properties on a class selector may make it difficult to re-use that class in other contexts, thereby requiring either duplicate CSS properties or overrides to achieve our goals.
He starts with a design of a promotional link like so:
.promo {
display: block;
padding: 20px;
margin-bottom: 20px;
background-color: #09f;
color: #fff;
text-shadow: 0 0 1px rgba(0,0,0,0.25);
border-radius: 4px;
}
It’s a full-width button, lovingly styled.
However, that single class is doing multiple things at once. But what if you wanted a similar promo link but wanted it inline? How do you solve that problem? Here’s his solution:
.island {
display: block;
padding: 20px;
margin-bottom: 20px;
}
.promo {
background-color: #09f;
color: #fff;
text-shadow: 0 0 1px rgba(0,0,0,0.25);
border-radius: 4px;
}
Boom! The promo class can be used in both inline and block contexts. The island class creates the block context.
In the HTML, we can now handle the two scenarios we want:
<a href="..." class="island promo">Buy Now!</a>
<h2>You should <span class="promo">Buy Now!</span></h2>
Breaking it down
In this case, the CSS has been broken down into two use cases and we have two CSS classes that serve this purpose. Excellent!
But wait, there’s more. There are a bunch of things that I might want to set consistent margin and padding to including inline-block
and flex
items. Maybe I should break things down even further?
.block {
display: block;
}
.spacing {
padding: 20px;
margin-bottom: 20px;
}
.promo {
background-color: #09f;
color: #fff;
text-shadow: 0 0 1px rgba(0,0,0,0.25);
border-radius: 4px;
}
<a href="..." class="block spacing promo">Buy Now!</a>
<h2 class="spacing">You should
<span class="promo">Buy Now!</span></h2>
As a project gets more complex, there are going to other ways to break down classes into smaller and smaller components. Which, ultimately, leads you to Atomic CSS, where each class has a very discreet purpose with, usually, just a single property.
<a href="..." class="D(b) P(20px) Mb(20px) Bgc(#09f) C(#fff) Bdrs(4px) Tsh(light)">Buy Now!</a>
<h2 class="P(20px) Mb(20px)">You should
<span class="Bgc(#09f) C(#fff) Bdrs(4px) Tsh(light)">Buy Now!</span></h2>
Which one is following the single responsibility theory?
Get Smacked
On the other end of the spectrum, is SMACSS. I advocate creating interface components that are independent of the content it’s trying to style.
Did you notice how there’s something that is made to look like something you can click on (the block link) but the other context was just inline text?
This whole scenario is made up but follow along here. If this were a design I received, I’d be going back to the designer and saying, why is it a link here but not there?
In other words, what’s the purpose of this style? It’s a button. Or a link meant to look like a button. In any case, calling it ‘promo’ is limiting. I’m probably going to want buttons all over the place. Or, if I don’t, at some point, I might. Therefore, I create a button style:
.button {
padding: 20px;
background-color: #09f;
color: #fff;
text-shadow: 0 0 1px rgba(0,0,0,0.25);
border-radius: 4px;
}
.button-full {
display: block;
margin-bottom: 20px;
}
This is very similar to what Harry had originally written but with different names. Also, I moved the CSS properties around. I want the padding on the button in both contexts but only when it’s full-width do I want it to have the extra margin on the bottom.
The naming convention I used was on purpose. They both start with button. One is the core module name and then the other can be layered on top of it.
Where I apply the single responsibility theory is in saying that an HTML should only have one module applied to it. Island and promo on the same element? Nope. But button and button-full? Climb aboard!
This narrow example gives me pretty much the same results that Harry did but with a bit more consideration added as to why things have been split up the way they have.
It’s one of the reasons that I continue to stick with the categorization that I originally defined in the book, with layouts, modules, states, and themes. There are patterns that reveal themselves in each of these categories.
Which way?
I’m not sure Harry expected to have his example nitpicked and there might’ve been a degree of pointlessness in my doing so. What’s the point of all this then?
There’s no right or wrong here.
Whether you use Harry’s approach, Atomic CSS, or SMACSS, could depend on any number of factors including comfort level and what you’re willing to trade off. Each could be argued as having or not having applied the single responsibility principle to their project.
Knowing which approach you want to take and how to break up your CSS comes from experience. You start to get a feel for where to draw the lines between which properties should go with which classes based on what was painful the last time you built a site.
Conversation
Definitely more of a SMACCS guy than Atomic. Atomic reminds me of Semantic-UI naming conventions. Name it what it is, and thats it.
So, I might have a stackable grid with the classes "stackable" and "grid". Thats fine and all but I find myself convoluting the classes with more detailed elements. SMACCS solves that problem by keeping everything in order and abstracted. Anyways, just wanted to say how much I love this idea. Trés bon!
Good to hear, Grant!
I don't see how the class
C(#fff)
is different from the HTML attributecolor="#FFFFFF"
from the days before CSS. To change the color to something else you're editing template files and individual pages rather than a single stylesheet!I also don't necessarily agree with “HTML should only have one module applied to it.” For example, if the attributes of the
.button-full
class are a common pattern, that class should be renamed appropriately and be able to be reused on more than just buttons. If you do need to use more linear, intuitive naming schemes for the HTML writers, a Sass mix-in could re-create the module modifiers while keeping the stylesheet DRY; if that pattern changes in a redesign it is modified in only the one spot.Having seen Harry Roberts give a talk last year (2015) I heard him mention that we was moving more towards an atomic level (He did not mention atomic). When doing some work for the NHS Harry found it much easier to create smaller modular class names that could be applied as helper classes.
From my point, I still struggle with these principles given a design I will add a structure class and a generic style class and then try to DRY up my code by moving some of the declarations into global classes.
Generally I end up mixing these principles up, I have a text-left/text-right to modify content and over-ride styles but I will still create a component style that aligns the text left without the helper class and content that more or less sticks with the SMACSS categorisation.
As long as once I'm finished the CSS is maintainable and understandable by the next developer then I'm a happy bunny.