Posted on
CSS Architectures for UI developers
Writing good CSS (or whichever sub-flavour) requires a good level of experience.
In this moment of time, we are still trying to figure out the best way to scale CSS allowing maintainability and readability without sacrificing performance and ease of use.
Some good practices first, then methodologies and systems have been created. Learning, if not mastering them will allow you to approach any CSS framework or library, being it legacy or open source and create new ones with - still relative, ease.
What are we talking about
If you are a front-end developer and worked implementing layouts and user interfaces, you might have heard of BEM, OOCSS, ITCSS, SMACSS and perhaps others.
There are different reasons why you want to use one or the other, but I’ve hardly seen any breakdown of these reasons.
Why do you even have to be bothered to choose one or the other?
There are mostly three areas we are talking about here:
- Naming conventions
- File organisation
- Overall architecture
The techniques we will discuss here, incorporate one or more of these points, and it’s somewhat hard to understand what’s working and why.
Remember that there is no silver bullet, and I’d encourage you to do a breakdown and analysis of what you need to build.
So let’s see what we have and what is needed.
I’ll try to progress from the simplest part, naming conventions, and progress further on the most generic level, to CSS architecture and others related to Design Methodologies.
How to name things
I’m assuming that you have a clear understanding of what semanticity of CSS means.
The article About HTML semantics and front-end architecture by Nicolas Gallagher provides a good overview. To keep it short, we are dealing with developer-oriented semantics, that is, names that make sense to whoever is going to consume your code, being someone else on the Internet, in your Company or your future self.
As soon as you start working with HTML and CSS you will be presented with the concept of classes and IDs as a way to style your content, and we’re left pretty much free on how to name things.
The key concept behind using appropriate names in classes and IDs is for its readability and maintainability: a correct use of naming conventions will help anybody understand where is something you need or why the class you’re looking at shouldn’t be used in a particular way.
We’re using names, nouns, to identify what we’re using and its scope, providing “implied” documentation on what we’re styling. It also helps us define the domain in which we’re operating, for instance, layouts elements, using names like `grid`, `row`, `cell`, or UI elements, with `button`, `dropdown`, `widget`, and so on.
We’re using adjectives to define a particular state, being it `enabled`, `valid`, or `is-selected`.
We need to be as much descriptive as possible and avoid being too generic at the same time.
Recovering from a bad name decided months prior can cost us dearly.
We can’t talk about how to name things, without understanding first what are these things.
Creating Blocks
What’s the smallest piece of information we should be styling?
One system that is very clear in how we define our classes is BEM, the acronym for Block-Element-Modifier. With it anything can be a Block, in turns the Block can contain Elements, and if we have any sub-content that we want to style we have to break it down creating a new Block or a new Element.
BEM is probably one of the most successful systems created since it’s quite precise in its definition, but it’s not perfect, as we can see:
- Names can possibly end up to be (very) long, e.g.
product-widget__calendar--compact
, which can cause some problems if size is an issue; - Does not separate layout information from the rest and it’s usually something left to the authors to define and whether to have it at all;
- Once again leaves up to interpretation everything else that is not a “block” or an “element”, so global style modifiers or
clearfix
have no defined position; - Modifiers can cause repetitions and their chaining (e.g.
class="block__element block__element--modifier"
) can cause some additional size and readability problems;
Might require some architecture analysis to avoid refactorings due to limits to depth nesting.
Are Layouts Blocks?
As an alternative to BEM, Jonathan Snook published a book on a Scalable and Modular Architecture for CSS, or in short SMACSS a while back, when SCSS wasn’t yet around, and still survives unscathed.
In it, we have a separation between Modules and Layouts, where Layouts are by all means elements that provide structural organisation and support for the Modules.
SMACSS provides a verbose and a more articulated naming convention, which probably caused BEM to be more successful over the years.
On top of that, the idea of the layout is a bit too well defined and sometimes separating the two might be a bit tricky.
SuitCSS seems to be taking the basics from BEM and adds a few more things to it, namely more clean and reusable element state modifiers, utility classes and prefixes to highlight layouts and responsive elements.
The system seems to be a bit more simple compared to SMACSS, but it still tries to push for a hard separation of layout elements, and as we will see, introduces some contextual information with the responsive prefixes that could cause more harm than needed.
Usually, we would define a three column grid as simply as the following:
.row {
@include container;
&--three-columns {
@include pad($gutter);
&__item {
// context is active, gutter is defined on a 12 column grid
@include span(4); // same as span(4 of 12)
}
}
}
In order to get the row--three-columns
work inside another block, we would have to add some more styling information in the definition, thus possibly departing from its original intended use.
To make matters worse, any slight modification on the way the container and its elements would look inside a block could cause us some serious problems.
As an example of possible real-world scenarios, we could:
- Add new contextual information within the element, either breaking the 2 level nesting rule we wanted to have and possibly making it behave in a completely different way than the one originally intended,
- Create a brand new item, thus duplicating the styling information of the original one,
- Create new complimentary classes to allow the styling to be modified, possibly once again invalidating the original scope.
So is it really important to separate layout modules from blocks/elements modules?
The widespread use of BEM seems to suggest the opposite and I wouldn’t personally mind too much given the following:
Every module definition should do one thing and only one.
But as we saw in our previous example, where do we draw the line between the “layout-module” and the “block-module with layout information in it”, like could be a gallery or a collection of CTAs?
For this reason, it’s probably important to understand the underlying concept of Separation of Concern and the Single Responsibility Principle.
SoC and SRP
Both BEM (and SMACSS for the most part) are essentially based on the concept of Separation of Concern [SoC].
SoC pushes us to understand the logical visual architecture, rather than its content. E.g. in the most basic of its terms, a “news item” might well be called article
instead of news-piece-1
, but that’s about it, so the rest is up to your ability to organise the information architecture.
The Single Responsibility Principle [SRP], embraced by OOCSS and Atomic CSS (not to be confounded with Atomic Design), can be considered the antithesis of SoC and it brings the context into the markup. This is particularly evident when it comes to a simple grid definition or some text styling.
As an example:
<div class=”col-lg-6 col-xs-2”>
<h4 class=”fs-15 ff-alt style-italic”>Subheading</h4>
<p class=”text-justified”>...</p>
</div>
Twitter Bootstrap uses this approach and you can read more in <a href="https://www.smashingmagazine.com/2013/10/challenging-css-best-practices-atomic-approach/" title="Challenging CSS Best Practices>this article that was published in 2013, which was being used in My Yahoo at the time.
Nowadays there are a lot of examples and projects that promote this approach so let’s see what are its pros and cons.
While this latter approach seems to be the developer’s and caching enthusiast’s dream, it poses the following problems:
- The markup will bear a lot of styling information that can cause problems in the long run: e.g. modules can be hard to be reused and contextual overriding will become hard to follow.
- Approaching a style guide for a large website from a developer perspective can result in a steep learning curve.
- Similarly, can cause some difficulty for whoever is not familiar with the naming conventions, or if these conventions grew up out of control. E.g.
pw-narrow
: is it product widget? Or is it defining a special password input?
If you want to read more about it, there’s a brilliant article by Ben Frain about what’s wrong with it, titled OOCSS/Atomic CSS are Responsive Web Design 'anti-patterns'.
SoC, on the other hand, wants to keep the markup clean, but makes reusability of CSS classes hard and could potentially introduce a lot of repetitions.
An adequate and large CSS framework uses a combination of both, on one side trying to simplify the markup, keeping it as much semantic as possible and allowing as much simplicity of the CSS modules at the same time.
This is essentially the main problem with CSS and why we still require a certain level of expertise to overcome the above problems.
In my opinion, this whole idea is currently flawed, as it relies on the developer alone to define how modules and the infrastructure works.
A design system is something that should seek participation from both the designer and the developer with an equal amount of knowledge of the aforementioned problems.
This is probably the reason why design system architectures have been envisioned since they shift the point of view to a more high-level and possibly correct point of view.
So, let’s see what’s available.
Beyond the defined styles
So far we’ve seen how naming conventions help us decide how to break down our layouts and organise the core of our style sheets. But if you’re worked enough with *CSS you are aware that there are other parts that you have to factor in when you start.
ITCSS does two things: provides a more organised file organisation and structure, while trying to optimise the selector distribution in a more linear way. It takes inspiration by analysing the increasing specificity of the selectors usually found in complex websites.
Of the two, the biggest addition compared to any other methodology seen so far, has been the introduction of everything else that we don’t normally talk about: settings, fonts, libraries, mixins, and trumps.
In the definition of the Objects and the Components, the author of ITCSS is very much inclined in adopting BEM and increase specificity as you move down the triangle, in a very similar fashion as you would do with OOCSS and possibly incurring in the problems I’ve highlighted before.
ITCSS has helped a lot to start standardising the file architecture and organisation of our projects. As per the specificity part, it’s not uncommon to see it ignored in favour of other approaches.
Overall Architecture
A not so recent way to define, organise and categorise the various modules has been Atomic Design. It provides a simple 3-layers system defining Atoms, Molecules and Organisms.
On the other hand, it does not prescribe where you are supposed to draw a line between them in a complex content structure. In other terms, it’s very much down to the developer to decide whether we want atoms just as single elements, or as a group of elements that are going to be used in an atomic way too.
If we follow through, the distinction between molecules and organisms is very much similar and fragile.
Because of this flexibility, Atomic Design can play well along with different naming conventions, like BEM.
It’s also entirely possible to overlap Atomic Design on top of ITCSS, for instance by replacing the Base, Objects and Components with Atoms, Molecules and Organisms, and adopting BEM as a way to deal with specificity.
I’ve been very much in favour of this organisation and methodology for quite a while now.
But nonetheless, the two main problems seem to be:
- The sheer amount of time needed to pick up the concepts and apply them consistently (taking into consideration that the effort spent to learn BEM and ITCSS is very small).
- In order to use Atomic Design to produce both a Brand Styleguide and a Developer Tool could require some additional efforts and might produce some messy results.
Predix Design System
Jeff Crossman in his article about the Predix Design System, analyses and takes the best and enhances Atomic Design concepts, with a clear idea in mind: the naming convention that Atomic Design adopts, as we’ve seen already, doesn’t help much and makes the learning curve and workflow somewhat painful.
In the Predix Design System what we highlighted before is now well defined due to the fact that we lose the distinction between organisms and molecules.
It also makes much more clear the use of Pages as Features and introduces Applications, i.e. actual use cases that helped build a product giving a better purpose.
From a higher perspective, it defines clearly the separation between the style guide as a developer tool, and as a Brand Guideline to be used by designers and others in the business, which wasn’t clear in Atomic Design.
Where are we going from here?
As we’ve seen so far you have plenty to choose from when deciding what to use for your CSS (or SASS) code base, and it’s also worth to notice that there is no silver bullet that can solve all the problems.
This means that sometimes you can come across projects that take a pinch of this and that methodology or system, sprinkle it with other definitions and repackage everything.
Although this might be alluring to some experienced UI developers, I cannot avoid thinking how much it would take to pick up all the methodologies and apply them for a novice approaching the system. Not only, a combination of the various systems might affect the scalability of your library and cause more trouble than what it actually tries to solve.
If I were to suggest anything right now I would suggest avoiding mixing too many, probably picking BEM as a generic naming convention, and apply it on top of Atomic Design or Predix Design System, depending on the scale of the project (e.g. if you need just a developer-focused system or if it’s going to be something much larger).