SMACSS methodology

In this post I will discuss the SMACSS methodology – Scalable and Modular Architecture for CSS. The name alone explains the purpose of its introduction – the creation of a scalable CSS architecture divided into modules to obtain a reusable code. This methodology has a dedicated book, which is a great source of knowledge about it. Its author and creator of SMACSS, Jonathan Snook, as he admits himself, drew inspiration from OOCSS approach, which is why you can find some similarities between these methodologies.

Concept

The main concept of the SMACSS methodology is to divide the CSS code into five categories:

  • Base
  • Layout
  • Module
  • State
  • Theme

so that our CSS file (or files, because each category can have its own dedicated CSS file) gets a clear, readable structure. And the code itself is divided into specific responsibilities. We will now discuss each of them.

Base

It defines the default style of HTML tags on the page and only tags. You can’t style class selectors and IDs. In addition, nesting should be avoided, but you can use attribute selectors or pseudo-classes freely. Let’s look at the following examples:

body {
    width: 100%;
    height: 100vh;
    margin: 0;
    padding: 0;
    background-color: #FFF;
}

input[type=text] {
    margin-left: 4px;
    padding: 8px;
}

button {
    padding: 8px;
    background-color: #2465B5;
    color: #FFF;
    transition: background-color 0.5s ease-out;
}

button:hover {
    background-color: #337CD6;
}

The purpose of base styles is to create predictable, basic views for an HTML tag no matter where on the page it will be placed. You can see similarity to CSS resets, however, it is discouraged in this methodology due to lack of control over resets and too aggressive reset of characteristic for the rule browser.

Layout

The responsibility of the layout styles is to properly position the elements on the page, creating its structure, the grid in which specific modules will be placed. Elements belonging to this group include footer, header, sidebar, nav or article. In this group, we can divide into reusable elements and those that appear only once on the page. In the first case, styling is done only with classes, and in the case of the second with classes or ID selectors (this is the only situation where we can style using ID). Let’s look at the examples presented in the HTML and CSS code:

<body>
    <header id="header"></header>
    <main id="main">
        <article class="l-article"></article>
        <article class="l-article"></article>
    </main>
    <footer id="footer"></footer>
</body>
#header, #footer, #main {
    margin: 10px auto;
    width: 800px;
}

#main {
    display: flex;
}

.l-article {
    width: 50%;
    display: flex;
    justify-content: space-between;
    border: 1px solid #337CD6;
}

In the above code, we see one characteristic example: .l-article . It is related to the proposal introduced in the SMACSS methodology, namely the classes that make up the layout have a prefix in the name, e.g. .l- . This rule doesn’t apply to the names of ID selectors.

It is also worth mentioning a possible situation when the layout styles at a higher level affect layout styles at a lower level. Let’s look at the above example when both article tags are inside the main tag. By default, the articles will be next to each other. It may happen, however, that we will want them to be under each other. We can do it in two ways:

  • give the articles a width of 100%, which means that both will have a width of 800px,
  • add the flex-direction: column rule to the main tag, so that the articles will still maintain their width, but they will be one below the other.

Second way

Let’s focus on the second way. We treat it as a layout case and use it with other styles in this group. We then add a class that will modify the main element to get the intended effect:

<main id="main" class="l-flattened">;
    <div class="l-article"></div>
    <div class="l-article"></div>
</main>
.l-flattened {
    flex-direction: column;
}

Let’s take it a step further – what if we want to make modifications to the structure of the articles during this change, for example, move them to the right? Should we create the l-article-flattened class? This is a possible solution, although we can use nesting:

.l-flattened> .l-article {
    margin-left: auto;
}

We could also do this using align-items: flex-end in the .l-flattened class.

As we can see in the above example, the SMACSS method allows for the parent’s layout to be influenced by the child’s layout and allows for the non-flat structure of the CSS file.

Module

This is the largest group of styles found in the application. Modules represent separate, independent page fragments that create specific functionality. These are the elements that build the entire functional layer of the page. We place them inside a grid built in layout styles or inside other elements in this group.

According to the SMACSS methodology, modules are styled only with classes, because the modules should be reusable. In the case of elements inside the modules, the styling issue is a bit more complex.

First of all, we can create separate classes for each of these elements, thanks to which we will maintain a flat structure (it is strongly recommended to use semantic class names).

Secondly, we can use the nesting of these classes inside the class of a particular module, thanks to which we will obtain a certain encapsulation of the styles of a given module.

Thirdly, acceptable (though not recommended) is the use of nesting along with styling using HTML tags, in this case we limit ourselves to only the first level of nesting. Let’s illustrate this on examples.

We have the following HTML snippet describing the module:

<div class="l-article">
    <article class="post">
        <header class="post-header">
            <h2 class="post-title"></h2>
            <span class="post-author"></span>
        </header>
        <section class="post-body">
            <img class="post-image" src="...">
            <div class="post-content">
                <p class="post-paragraph"></p>
                <p class="post-paragraph"></p>
            </div>
        </section>
        <footer class="post-footer"></footer>
    </article>
</div>

Possible solutions

Let us now introduce possible solutions to the styling of elements based on the three mentioned cases. First:

.post {}
.post-header {}
.post-title {}
.post-author {}
.post-body {}
.post-image {}
.post-content {}
.post-paragraph {}
.post-footer {}

We see that we maintain a flat structure of the CSS file, moreover, the classes are called semantically and, looking at them, we know what to expect from the code that they style. This is my favourite way due to the monotonous level of specificity.

Let’s move to the second, very similar way:

.post .post-header {}
.post .post-title {}
.post .post-author {}
.post .post-body {}
.post .post-image {}
.post .post-content {}
.post .post-paragraph {}
.post .post-footer {}

An unquestionable advantage is the closure of the styles of elements of a given module within its class. We could further develop the above method:

.post .post-header {}
.post .post-header .post-title {}
.post .post-header .post-author {}
.post .post-body {}
.post .post-body .post-image {}
.post .post-body .post-content {
.post .post-body .post-content .post-paragraph {}
.post .post-footer {}

However, it leads to an increase in specificity, which may not be desirable. The last method is as follows:

.post> header {}
.post> section {}
.post> footer {}

Its disadvantage is we lose control over what elements we set out and which ones we don’t. Imagine a situation that there will be two section tags and both will be spelled out in the same way. This will not always be our intention.

Variations

There remains one more issue related to the modules – their variations. Often in applications, the component used several times must look different, depending on the location where it is located (it may not have as much space as it normally needs) or depending on the context in which it is located. We call such modified modules sub-modules and the classes modifying the basic appearance – sub-classes. They are used together with the basic classes. Let’s illustrate this with an example:

<article class="post post-bolded">
    ...
</article>
.post {
    border: 1px solid #000;
    font-weight: normal;
}

.post-bolded {
    border: 2px solid #000;
    font-weight: bold;
}

A good test for our code whether we have correctly separated the modules is to move it to a separate place on the page – if the appearance of this module doesn’t break down, it means that we have done our job well.

State

This style group is responsible for the specific states of the appearance of modules, base elements or even a layout. Importantly, they take precedence over other styles (regarding appearance). As the only of the existing groups is closely related to the JavaScript code, which modifies the status of elements by adding or removing classes representing a specific state. Very often, the names of such classes are preceded by the expression is- . Examples of names:


.is-collapsed {}
.is-expanded {}
.is-active {}
.is-highlighted {}
.is-hidden {}
.is-shown {}
.is-successful {}

In accordance with the fact that the styles included in these classes are to cover styles from other groups, the use of the !important directive is allowed or even recommended. Note, however, that using a flat CSS file structure with defining state classes at the very end of a CSS file avoids the use of this directive.

It may also happen that a given state is strictly characteristic for a given module, which makes it unnecessary to generalize it for the whole application. In this situation, in the name of the class, we consider the name of the module and place this class among the classes related to this module. Let’s present it with an example:

.post {}
.post-header {}
...
.is-post-highlighted {}

The second possible way is to nest the state class inside the module class:

.post .is-highlighted {}

Theme

Its responsibility is to define the colour of the page and the media appearing on it (photos, video, audio). There is a possibility of defining this type of rules in modules or layout. That’s why the occurrence of this group is optional. Separating these styles, however, allows you to quickly modify the entire layout of the page. Styles from this group can override styles from other groups (as part of its responsibility), including state styles. There is no naming convention for classes, because according to the guidelines we use existing classes, for example:

.post {
    border-color: red;
}
.post-header {
    background-color: blue;
}
.is-post-highlighted {
    background-color: green;
    color: white;
}

Grouping parts of a graphical appearance in one place is convenient for a programmer when it comes time to change appearance. Especially in large projects.

Naming

The SMACSS methodology doesn’t introduce a strict naming convention for individual groups. It only recommends creating one set of rules and sticking to it in the whole project. We can present this on the example of layout styles. Each of the below given names is equally good, because it shows well what group we are dealing with:

.l-article {}
.layout-article {}
.grid-article {}
.str-article {}
.structure-article {}

Choose one version for a given group and use it only. However, I would like to pay special attention to the way we will call the module classes. The practice indicates that it is a very good solution to use semantic names for this group. It is because of the components form the main content of the page. It is also worth reflecting in the CSS files.

Summary*

In this entry we learned the SMACSS methodology. 5 rules governing the creation of a CSS file / files and a naming convention. Below I present a short summary of the article:

You can find demo of an application created with this methodology here.

The next entry will be about Atomic Design. If you want to go deeper into the ins and outs of SMACSS, go here.

* In the summaries of the methodology entries, I omit the presentation of their advantages and disadvantages. I want to leave each of you the opportunity to evaluate independently.

If you want to know more about CSS Methodologies, read previous articles from the series:

Tags:

Michał Wajer

Software Developer at Aspire Systems Poland. He began his adventure with Angular in the summer of 2018. In his free time, he learns the secrets of Vue, RxJS and TypeScript. Enthusiast of sport (most of all running) and speedway.