DEV Community

Cover image for Implementing SMACSS: A Scalable And Modular Architecture For CSS
Harish Rajora for LambdaTest

Posted on • Originally published at lambdatest.com

Implementing SMACSS: A Scalable And Modular Architecture For CSS

When we talk about an application’s scalability, we rarely bring CSS into the picture. Scalability typically raises concerns about the system’s design, resource management, monitoring, and, of course, query time limits. But have you ever pondered the measures we should take while developing CSS with scalability in mind? CSS becomes more tangled as a website expands in size. While best CSS frameworks like Bootstrap are useful, SMACSS, also known as Scalable and Modular Architecture for CSS, uses a unique approach, functioning as a collection of guidelines to classify your CSS rulesets to make the CSS codebase more scalable and modular.

A CSS architectural specialist, Jonathan Snooks, authored SMACSS: A Flexible Guide for developing large and small websites.

The book’s notes will constitute the basis of this SMACSS tutorial, shedding light on why excellent CSS writing standards are vital and how they help maintain a scalable application.

Let’s begin!

Hey! Test your Servicenow CSS framework based websites across 3000+ different desktop and mobile browsers with Online Servicenow Testing Cloud, a scalable and reliable online testing cloud for both manual and automation testing of Servicenow websites.

What Is SMACSS?

SMACSS is an acronym for Scalable and Modular Architecture for CSS. In simple terms, SMACSS is a collection of handy guidelines that teach us to write scalable and readable CSS.

So here comes the question: Is SMACSS important in the web development industry? A short answer is — only if you think your web application will scale in future. The ideal approach is to consider building a web application that will eventually expand to a large size. More points could be made to elaborate on the factors that make SMACSS vital, but they will only make sense towards the end of this post.

SMACSS allows the highly readable creation of CSS. Let’s look at a web application where I was required to build two separate headers for regular users and an admin. As a beginner, my CSS for the user’s header will look something like this:

<style>
    h2 {
     color: red;
     font-size: 24px;
     font-family: xyz;
    }

    p {
    color: white;
    font-size: 14px;
    }

    </style>
    <h2>LambdaTest</h2>
    <p>SignUp Features Pricing</p>
Enter fullscreen mode Exit fullscreen mode

However, the above SMACSS example works fine as intended. When I jump over to the admin section and write CSS again, I might have to define other terms. So let’s experiment with admin-h2, admin-p.

<style>
    admin-h2 {
     color: red;
     font-size: 24px;
     font-family: xyz;
    }

    admin-p {
    color: white;
    font-size: 14px;
    }

    </style>
Enter fullscreen mode Exit fullscreen mode

In the above SMACSS example, if a third element comes into this scenario later, I might use the same convention and go through this complete process again. It doesn’t look awesome, but I am sure it will pass the checks now.

However, let’s say there is some styling that I want on A and B but not on C. Should I copy the styling again in both? Or create complex relationship logics using hereditary? This issue is with scalable operations. We have several things on our minds that when we return to our code after a month, we are perplexed by the method we used when developing it. SMACSS is designed to address such issues.

SMACSS book states a simple rule of thumb; if you think there will be collisions for the same element, keeping them in separate files is better. This creates a structured file system and manageable code at once. So, for example, when I need to search for something on the “blog” page, I can search at blog.css rather than a combined code.

The above things come under generic or basic guidelines to keep in mind while writing CSS codes. Apart from these, Jonathan has divided other points into five basic elements of SMACSS or a scalar and modular CSS. The rest of the guidelines I will describe in the coming sections of this SMACSS tutorial.

The Categorization Of CSS Rules Under SMACSS

Besides organizing our complete CSS code separately for better readability, Jonathan Snooks categorizes CSS rules into five categories. Before categorizing, he mentions, “By categorizing CSS rules, we begin to see patterns and can define better practices around each of these patterns.” This line summarizes quite well why we aim for categorization in CSS rules.

The five categories in which CSS rules are divided are:

  1. Base

  2. Layout

  3. Module

  4. State

  5. Theme

Let’s explore them one by one.

Base Rules

As the name suggests, the base rules need to be applied to the base elements of a web page. The below SMACSS example can be considered a part of base rules in SMACSS:

body {
      margin-left : 20px;
    }

    p {
    font-family: xyz;
    }
Enter fullscreen mode Exit fullscreen mode

We apply base rules to the elements that will remain consistent throughout the web page. In the above SMACSS example, we want the content to be displayed 20px from the left, and the paragraph element should have a certain “font family”.

You can also go for a descendent selector, child selector, and pseudo-classes, apart from the direct elements. However, while creating the base rules, Jonathan strictly restricts “! important” in any rules. This could be due to unwanted behavior displayed when our style starts overriding from different sections or specificity issues (discussed later).

You also need to avoid using CSS-resets, a popular approach, to reset the CSS before laying down your own. This increases the amount of code sent to the client from the server. Therefore, if there is any default setting that you want to create, the base rules are a great place to note them down.

Layout Rules

The second rule talks about designing the CSS for the layout of the web app. The major part of the web page is considered under the category of layouts. Designing CSS for them often poses challenges as there are a lot of elements involved, and defining each layout with multiple IDs makes things a bit complex.

A simple example of a naive CSS design is as follows:

    #header , #features, #sidebar {

    //STYLES
    }

Enter fullscreen mode Exit fullscreen mode

But the above naive CSS design will fail when we need multiple layouts based on multiple preferences. In such a case, a naming convention with the prefix ‘l’ can determine that this class selector is based on a layout element.

   #header {

    //style
    }

    #sidebar {

    //styles

    }

    .l-mobile #sidebar {

    //mobile-specific styling such as width

    }
Enter fullscreen mode Exit fullscreen mode

In the above SMACSS example, the l-mobile class determines that it has been constructed to change the “layout” of an element related to mobile. Therefore, the name “l” is not necessary to use in the layout rules of SMACSS. However, the author does recommend using it as a standard for better readability.

Module Rules

Modules are the smaller parts of the layout elements such as navigation, widgets, dialogues etc. Considering modules as part of the layout creates unnecessary complexity because modules are used at several places than large layouts. You can think of layouts as major layouts and modules as minor ones (referring to the book convention). Keeping them separate helps us achieve simplicity in the code.

Modules need to have a reusable code because of its high involvement on a web page. If we keep tagging IDs to different elements, again and again, we will be in a trap before we realize. The better method is to use class selectors and child elements or any other inheritance in the code.

.module > h2 
    {
    //style code
    }

    .module span {

    //styling code

    }
Enter fullscreen mode Exit fullscreen mode

The above-given approach is good only in two cases. First, when the relationships are extremely clear, the developer is confident that newer relations won’t arise. Second, the child selector you have used will not be confused and modified with other children of the same parent. This approach is a simplified example and can easily get confusing as our project grows. For SMACSS example, one more relation can be added as follows:

.module h2 #heading-top {

    //style

    }

Enter fullscreen mode Exit fullscreen mode

Such arrangements collide with each other and lead to specificity issues. To abstain from letting the browser decide, we often go for the !important approach, which is extremely dangerous, especially for larger projects. The better solution to this is using subclasses.

CSS subclasses can divide styling among each other, simplifying the relationships between children and their parent(s). For example, if the parent element always has to be red, but children will have different fonts, we can create subclasses.

.heading {

    //style

    }

    .heading-email {
    //style
    }

    .heading-news {

    //style

    }

Enter fullscreen mode Exit fullscreen mode

Using this approach mixed with subclasses, we can define one standard styling for the header and change the email and news header fonts or any other style specifically. In the HTML, we just have to use both the classes:

 <h3 class = “heading heading-email>This is email header</h3>

Enter fullscreen mode Exit fullscreen mode

Now we can create a sorted document without any coupling between the elements.

Did you know that you can now test your Shopify CSS framework based websites across 3000+ different desktop and mobile browsers with Online Shopify Testing Cloud, a scalable and reliable online testing cloud for both manual and automation testing of Shopify websites?

State Rules

After we have carefully crafted the layout and module rules, we need to take care of the design of the state of the element. A state rule is applied when an element has multiple states. For example, a module can be in an error state (depending on the error received) or a success state. For both of the states, the module needs to render different styles. This is where state rules come in.

In this complete document, the focus has been increasing the readability of CSS and simplifying the style sheet as much as possible. On the same thoughts, consider the following code:

<div>
        <div> This is an error </div>
        <div> This is a success </div>
    <div>
Enter fullscreen mode Exit fullscreen mode

I have excluded every selector from the above code as this code changes state from error to success depending on the user action. Can you take a moment and think about what classes can be attached to this code that satisfies SMACSS guidelines?

Taking notes from the module rules, it is always better to separate things when we know some style will stay stationary after the CSS has first loaded. So that becomes our parent element.

.application-form {

    //style

    }
Enter fullscreen mode Exit fullscreen mode

For the state classes, it is always better to use names that define state even if the reader has no idea about it. For the SMACSS example, we have two states in the above code — error and success. Hence, the following classes can be attached:

.is-error {

    //style

    }

    .is-success {

    //style

    }
Enter fullscreen mode Exit fullscreen mode

We can combine them with other modules or layout classes to give a meaningful design to the client machine.

<div class = “application-form“>
        <div class = “msg is-error”> This is an error </div>
        <div class = “msg is-success”> This is a success </div>
    <div>
Enter fullscreen mode Exit fullscreen mode

Note: The msg class can be a message styling class that generates some message design.

So, what is the difference between module rules and state rules? They do look similar, don’t they?

For two very important reasons, module and state rules are similar in working and styling. The lesser important reason is that they are “states” of a module or layout. Hence they are defined within these elements and prefer a different naming as seen above. They are attached within these modules and layouts and increase readability and simplicity.

The more important reason for using the state rules is the JavaScript-based changes that run on the client-side based on the user’s response (hence we cannot lay down the rules from the server). The JavaScript code can catch the elements and apply appropriate classes to them by their current state.

Jonathan has repeatedly shown his disinterest towards using the !important attribute as it hinders the specificity of the code. But while stating state rules, Jonathan finds it important to make use of !important as we know that one element can be in only one state during execution. Hence, it becomes necessary that the state rules we are trying to apply do not override other rules.

Theme Rules

As the name suggests, theme rules are defined for the theme of the web application. For example, every website has a theme reflecting business or based on other strategies. The theme design remains consistent throughout the web app, no matter what module you are in. A classic example of theme design is typography. CSS Typography often helps connect with the user, and if you are using a unique font style, users generally remember it well after they have closed the browser.

Theme rules are not considered core rules as the author considered the previous four. The reason is that they are not required for every web-based project. Theme layout has no special guidelines except to keep them in separate files for simplicity. Since class names can sometimes be similar, it provides a clear distinction between layout classes, module classes or theme classes.

As a web developer, keep the bigger design things in the theme classes to remain consistent. For example, the background color of each module may be different, so keeping them in the module CSS makes more sense. At the same time, the borders of each module might remain consistent with showcasing the website’s theme. Therefore, it should be kept in the theme rules file.

Concerns About The Depth Of Applicability

Now that we are done with the rules part in this SMACSS tutorial, we need to move a step ahead and analyze how to use them to generate a better CSS. The depth of applicability is the number of generations affected by a single rule.

Check out the following CSS rule:

#sidebar  div h3  #header-style {

    margin: 15px;

    }

    #sidebar  div h3  #header-style div {

    color: red;

    }
Enter fullscreen mode Exit fullscreen mode

The above rule has a depth of 4 generations. Here we are associating too many elements with each other and increasing the complexity of the document. This will increase dependency on the HTML elements and force us to duplicate them in the document. For example, if we want to have the same layout for the footer, we might duplicate all the elements.

#sidebar  div h3  #footer-style {

    margin: 15px;

    }

    #sidebar  div h3  #footer-style {

    color: blue;

    }
Enter fullscreen mode Exit fullscreen mode

To avoid such complexities, we can use classes and decrease the depth of applicability in the document.


    .abc {

    margin: 15px;
    }

    .abc > #header-style {

    color: red;

    }

    .abc > #footer-style {

    color: blue;

    }
Enter fullscreen mode Exit fullscreen mode

The above SMACSS example code is more flexible, and the depth of applicability is shallow. In a scalable project, such relations will save a lot of time for the developer and code readers or reviewers.

Are SMACSS Rules Important In Web Development?

SMACSS is different from the concept like CSS Grids. SMACSS is an extensive approach towards writing CSS and making it more efficient. A thing to note is that SMACSS does not decrease the running time of CSS on a web page. But, it saves a lot of time when developers are looking for a bug. This is called maintenance, and it is expensive in the IT industry, just like the module rules.

The following code exists on Amazon’s home page:

In the above code snippets, you will find many classes used for different purposes, but since all the elements belong to the navigation bar, they start with the word “nav”. You can also find a state rule here. The sole purpose of the above example is to show you the code readability.

After implementing SMACSS, you can perform browser compatibility testing using cloud-based platforms like LambdaTest to ensure that it renders correctly on different browser versions and operating systems. LambdaTest is a cross browser testing platform that provides 3000+ browsers and operating systems to test websites and web apps for browser compatibility issues in CSS.

LambdaTest also comes with an add-on tool, LT Browser. It is a mobile-friendly checker tool that provides 50+ pre-installed viewports for Windows OS, macOS, Android, and iOS to perform the responsiveness test of your websites and web applications.

If you are intrigued to know more about LT Browser, refer to our LT Browser video tutorial to get started with the responsiveness test right away.

However, you can go through the LambdaTest YouTube Channel and stay updated with more such videos on Selenium Testing, Cypress Testing, and more.

Hey! You can now test your Wix CSS framework based websites across 3000+ different desktop and mobile browsers with Online Wix Testing Cloud, a scalable and reliable online testing cloud for both manual and automation testing of Wix websites.

Conclusion

The main goal of SMACSS is to increase readability, efficiency and, if I can say, improve you as a web developer (and definitely as a programmer). SMACSS is prominent as it’s now expected to be in the habit of every web developer. It can help you design things faster and take care of them with ever-changing technologies.

Top comments (0)