11. Maintainable CSS

Overview

By the end of this chapter, you will be able to write CSS code using the BEM approach and explain semantic CSS; describe componentization and rule grouping and apply these principles while writing CSS code; write maintainable SCSS with sensible file and folder structures; and implement CSS best practices to create better maintainable code.

This chapter introduces the concept of maintainable CSS in terms of what it looks like and how we go about creating it. With the knowledge that's given in this chapter, you will be able to create more manageable CSS codebases in SCSS and make your web projects more future-ready for changes and other developers to pick up easily.

Introduction to Maintainable CSS

In the previous chapters, we learned about a wide variety of different aspects of HTML5 and CSS3, including everything you need to know as a beginner to write HTML5 and CSS3 yourself and develop your first website, but how can we help keep a website maintainable? How do we help prevent the common pitfalls of managing large codebases in CSS? How do we write code that allows a team of developers to work on a website project at the same time and that's also friendly to future developers?

In this chapter, we're going to explore what maintainable CSS looks like, how to write it, and why we use it. Let's start by understanding why we would want to write maintainable CSS.

Say you are working with a large codebase that includes thousands of lines of CSS and the client wants to change a button style that's used throughout the website. Easy, right? Well if we had written maintainable CSS for this project, then we could change this button style in one of the SCSS files that the button component lived in, recompile the CSS, and then the job would be done. But if we didn't write maintainable CSS, updating this button style could mean updating many references in different places to ensure the button is changed globally across the website. This could involve writing overrides to force the button style to change and could end up being very messy and rather unmanageable. We could end up with even more lines of CSS overall for the browser to download, some lines of which probably wouldn't even be required anymore because they're related to the old button style. However, we wouldn't necessarily know where to remove it from if the CSS hasn't been maintained well, causing the codebase to become very bloated with old styles over time.

Good CSS coding practice when working in a team on a website development project is to ensure that any developer can pick up the code where you left off, with all the developers maintaining the same CSS standards to ensure that the codebase makes sense and that modifications can be made quickly, safely, and efficiently to minimize code debt (which, in short, means minimizing unnecessary code). We can understand how projects become unmaintainable if we consider reasons such as budget limitations or other pressures such as tight deadlines, which can make some developers write code that causes CSS code debt, or worse – unmaintainable CSS code.

Block, Element, and Modifier

The first stage of writing maintainable CSS is to write and use meaningful elements identifying rules. A maintainable approach for this is to use Block, Element, and Modifier (BEM). BEM is a semantic approach to identifying elements and applying CSS rules to them.

Semantic CSS means naming elements according to what they are, rather than what they look like. For example, using a class of .article-box instead of .blue-box on an HTML div element would allow the color property of the div to be changed later and it would still make sense semantically, given that the color wasn't associated with the selector name in the first place. Therefore, this helps make the code more maintainable in the future.

Let's explain each block that makes up BEM.

Block

This is the main entity and is meaningful on its own. This could be a header (.header), navigation (.nav), field (.field), article (.article), and so on.

Element

This would be a child of a block, based on a semantic meaning with block, and it wouldn't make sense by itself. Examples include header logo (.header__logo), navigation item (.nav__item), field label (.field__label), and article paragraph (.article__paragraph).

Modifier

This is a variation in a block or element and can be used to change its appearance or behavior. Examples include a header in a blue theme variation (.header--blue), a navigation item that's highlighted (.nav__item--highlighted), a field with a checkbox input with the state "checked" (.field__input--checked), and a button with a state of success (.button--success).

So, what does BEM look like when written to CSS? The syntax is as follows. To declare a block, you would write just the block name:

.block {}

To modify the appearance or behavior of the block, you would add a modifier:

.block--modifier {}

To style an element of a block, you would use the following syntax:

.block__element {}

To modify the appearance or behavior of an element, you would add a modifier:

.block__element--modifier {}

All of these CSS identifiers refer to the HTML classes that have been assigned and the styles that are inherited this way. Let's look at the HTML syntax of these rules:

<div class="block block--modifier">

    <div class="block__element block__element--modifier">

        <!-- content here -->

    </div>

</div>

Now, let's look at an example of BEM in action. First, we'll take a simple navigation structure and apply BEM to it. Let's start with the HTML:

<nav class="nav">

    <ul class="nav__list">

        <li class="nav__item">

            <a href="#" class="nav__link">Home</a>

        </li>

        <li class="nav__item">

            <a href="#" class="nav__link">About</a>

        </li>

        <li class="nav__item">

            <a href="#" class="nav__link">Contact</a>

        </li>

    </ul>

</nav>

You will notice how we haven't created "grandchild" selectors such as .nav__item__link as this becomes unnecessarily messy. An element only needs to semantically be related to one block to be maintainable. At this point, it's worth noting that you can create a new block within a block to ensure the code is more semantically relevant.

Now, let's create the CSS for our simple navigation structure:

.nav {

      background: black;

}

.nav__list {

      display: flex;

}

.nav__item {

    list-style: none;

      flex: 1 1 auto;

      border-right: 1px solid white;

}

.nav__item:last-child {

      border-right: none;

}

.nav__link {

      display: block;

      color: white;

      padding: 10px;

      text-align: center;

      text-decoration: none;

}

.nav__link:hover {

      text-decoration: underline;

}

Here, you can see what the CSS for the BEM marked up navigation looks like. The following screenshot shows how this would be displayed in the browser:

Figure 11.1: Navigation bar

Now, let's say we wanted to change an instance of the navigation and make the contact navigation link stand out more. First, we'd give the link a modifier class:

<a href="#" class="nav__link nav__link--contact">Contact</a>

Then, we can add a new CSS rule to make the link stand out more:

.nav__link--contact {

      color: red;

      font-weight: bold;

}

This would update the navigation to appear as follows:

Figure 11.2: Highlighted contact navigation link

If we wanted to change the appearance of all the links, for instance, use different colors and fonts for navigation that appears on a different part of the website, then we could apply a modifier to the block itself, rather than the individual element. The HTML could be changed for .nav by adding a new modifier called theme2, like so:

<nav class="nav nav--theme2">

We would then create a new CSS rule to apply the theme2 styling to the navigation bar. This would look something like this:

.nav--theme2 {

    background: lightgray;

}

.nav--theme2 .nav__link {

    background: lightgray;

    color: black;

    font-family: Arial;

}

The following screenshot shows the end result of the theme2 modifier being applied, the .nav styles being inherited, and the modifier changing/extending the styles to give a different appearance:

Figure 11.3: Navigation with theme2 modifier styles applied

Next, we'll look at putting BEM markup into action by practicing its use in an exercise.

Exercise 11.01: Using BEM Markup

The aim of this exercise is to get you writing maintainable BEM code, starting with some existing HTML and CSS markup, and transforming this into a more maintainable semantic BEM-based markup. Let's get started:

  1. Start your exercise with the HTML code in Exercise 11.01_Raw.html from https://packt.live/2X7JOQh. Save this as Exercise 11.01.html in a new folder called Chapter11.
  2. Next, we're going to create the exercise1.css file within a subfolder called css in our Chapter11 project folder. Save the CSS extract to your file from https://packt.live/32CC6yZ. This is shown in the following code:
  3. When you access Exercise 11.01.html in your web browser now, you should see a web page that looks as follows:

    Figure 11.4: Web browser screenshot

  4. Next, we'll be updating the HTML references in Exercise 11.01.html so that it uses BEM. The following is the updated HTML code:

    <!DOCTYPE html>

    <html>

    <head>

      <meta name="viewport" content="width=device-width, initial-scale=1" />

      <title>Chapter 11: Exercise 11.01</title>

      <link href="css/exercise1.css" rel="stylesheet" />

    </head>

    <body>

        <header class="header">

            <div class="logocontainer">

                <img class="logocontainer__img" src="https://dummyimage.com/200x100/fff/000&text=Logo" alt="Logo" />

            </div>

            <nav class="nav nav--header">

                <ul class="nav__list">

                    <li class="nav__item">

                        <a class="nav__link" href="#">Home</a>

                    </li>

                    <li class="nav__item">

                        <a class="nav__link" href="#">About</a>

                    </li>

                    <li class="nav__item">

                        <a class="nav__link" href="#">Contact</a>

                    </li>

                </ul>

            </nav>

        </header>

        <nav class="nav nav--subnav">

            <ul class="nav__list">

                <li class="nav__item">

                    <a class="nav__link" href="#">Sub Page 1</a>

                </li>

                <li class="nav__item">

                    <a class="nav__link" href="#">Sub Page 2</a>

                </li>

                <li class="nav__item">

                    <a class="nav__link" href="#">Sub Page 3</a>

                </li>

            </ul>

        </nav>

        <article class="article">

            <h1 class="article__title">Article Title</h1>

            <p class="article__text"><img class="article__image" src="https://dummyimage.com/200x100/fff/000&text=Demo+Image" alt="Demo Image" /> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam quis scelerisque mauris. Curabitur aliquam ligula in erat placerat finibus. Mauris leo neque, malesuada et augue at, consectetur rhoncus libero. Suspendisse vitae dictum dolor.</p>

            <p class="article__text">Vestibulum hendrerit iaculis ipsum, ac ornare ligula. Vestibulum efficitur mattis urna vitae ultrices. Nunc condimentum blandit tellus ut mattis. <img class="article__image article__image--right" src="https://dummyimage.com/200x100/fff/000&text=Demo+Image+2" alt="Demo Image 2" />  Morbi eget gravida leo. Mauris ornare lorem a mattis ultricies. Nullam convallis tincidunt nunc, eget rhoncus nulla tincidunt sed.</p>

            <p class="article__text">Nulla consequat tellus lectus, in porta nulla facilisis eu. Donec bibendum nisi felis, sit amet cursus nisl suscipit ut. Pellentesque bibendum id libero at cursus. Donec ac viverra tellus. Proin sed dolor quis justo convallis auctor sit amet nec orci. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>

        </article>

        <footer class="footer">

            <p class="footer__copyright">Copyright Text Goes Here</p>

            <nav class="nav nav--footer">

            <ul class="nav__list">

                <li class="nav__item">

                    <a class="nav__link" href="#">Footer Nav 1</a>

                </li>

                <li class="nav__item">

                    <a class="nav__link" href="#">Footer Nav 2</a>

                </li>

                <li class="nav__item">

                    <a class="nav__link" href="#">Footer Nav 3</a>

                </li>

            </ul>

            </nav>

        </footer>

    </body>

    </html>

    As you can see, all the navigation instances share the same .nav styles initially, but each unique instance has a modifier class (for instance, .nav--header) to tweak its appearance for that instance. We've added a modifier class to each of the reused nav blocks (for instance, .nav--header), so that we can reuse the .nav block as a reusable component. It's default styling rules (from .nav) can be inherited on the header (.nav--header), sub navigation (.nav--subnav), and footer (.nav--footer).

  5. Now, we'll update the exercise1.css file so that it matches the new BEM HTML markup. The following is the updated CSS:

    * {

        margin: 0;

        padding: 0;

    }

    body {

        font-family: Arial, sans-serif;

        font-size: 14px;

        color: #000;

    }

    .header {

      display: flex;

      align-items: center;

    }

    .logocontainer {

      flex: 0 0 auto;

    }

    .logocontainer__img {

      width: 100%;

      height: auto;

      display: block;

      border: 1px solid #000;

    }

    .nav--header {

      flex: 1 1 auto;

      text-align: right;

      padding-right: 20px;

    }

    .nav__list {

      list-style: none;

    }

    .nav__item {

      display: inline-block;

      padding-right: 10px;

    }

    .nav__item:after {

        content: '2022';

        padding-left: 10px;

    }

    .nav--subnav .nav__item:last-child {

        padding-right: 0;

    }

    .nav__item:last-child:after {

        display: none;

    }

    .nav__link {

      color: #000;

      text-decoration: none;

    }

    .nav__link:hover {

        text-decoration: underline;

    }

    .nav--subnav {

        text-align: center;

        background: #000;

        padding: 10px 0;

    }

    .nav--subnav .nav__item {

        color: #FFF;

    }

    .nav--subnav a {

        color: #FFF;

    }

    .article {

        margin: 20px;

    }

    .article__image {

        float: left;

        margin: 0 10px 10px 0;

        border: 1px solid #000;

    }

    .article__image--right {

        float: right;

        margin: 10px 0 0 10px;

    }

    .footer {

        background: #DDD;

        clear: both;

        display: flex;

        padding: 20px;

    }

    .footer__copyright {

        flex: 1 1 auto;

    }

    .nav--footer {

        flex: 0 0 auto;

        text-align: right;

    }

    You will notice that when using BEM in CSS, not much nesting is required, as we only need to nest when modifiers are used at a parent level.

  6. If you reload the Exercise 11.01.html file in your web browser, it should appear as follows. If this isn't the case, then you will need to recheck the HTML and CSS modifications that were made when you migrated this exercise into BEM markup:

Figure 11.5: Completed web browser screenshot

We've now completed this exercise and you should have a good understanding of what BEM markup is and how we can take existing HTML and CSS markup and convert it into the more maintainable BEM markup standard. Next, we're going to review how we can use BEM in SCSS.

Using BEM Markup with SCSS

Developing our knowledge further from Chapter 10, Preprocessors and Tooling, we're going to take a look at how we can write BEM in our SCSS code so that we can compile it into more maintainable CSS code. We can nest BEM elements inside the block with SCSS. For example, if we had the .nav__list element, then we could nest it inside a .nav block using the & syntax, as shown in the following example:

.nav {

      &__list {

          /* Styles Here */

}

}

Let's look at the sample CSS we had earlier in this chapter:

.nav {

      background: black;

}

.nav__list {

      display: flex;

}

.nav__item {

    list-style: none;

      flex: 1 1 auto;

      border-right: 1px solid white;

}

.nav__item:last-child {

      border-right: none;

}

.nav__link {

      display: block;

      color: white;

      padding: 10px;

      text-align: center;

      text-decoration: none;

}

.nav__link:hover {

      text-decoration: underline;

}

To achieve the preceding CSS output, we would write the following SCSS:

.nav {

      background: black;

    &__list {

          display: flex;

    }

    &__item {

          list-style: none;

          flex: 1 1 auto;

          border-right: 1px solid white;

        &:last-child {

            border-right: none;

        }

    }

    &__link {

          display: block;

          color: white;

          padding: 10px;

          text-align: center;

          text-decoration: none;

        &:hover {

            text-decoration: underline;

        }

    }

}

The SCSS is 9 lines and 146 characters more compact than the original CSS, so it's quicker to write and easier to maintain as it's still using BEM. As we discussed in Chapter 10, Preprocessors and Tooling, we can get our npm run scss command to output our CSS in compressed format too, thereby making the production website version super compact but keeping the SCSS file easily maintainable.

Next, we're going to look at adding the modifier class to the SCSS file. For example, if we had a modifier class of .nav__link--contact, then we could add this nested part of the &__link part of the SCSS, as follows:

.nav {

    &__link {

        &--contact {

          color: red;

          font-weight: bold;

       }

    }

}

The preceding SCSS code would construct the .nav__link--contact class and apply the bold format and red color to the text. If we added a modifier class to the block called .nav--theme2, and if we wanted to change the appearance of an element within the modified block, then we could nest the block modifier within the element SCSS, as shown in the following code:

.nav {

    &__link {

        .nav--theme2 & {

            background: lightgray;

            color: black;

            font-family: Arial;

        }

    }

}

As you can see in the preceding code, we are changing the font, font color, and background color of .nav__link if it's preceded by the .nav--theme2 block modifier class. We're going to put this into practice in the next exercise by updating our CSS and making it into SCSS.

Exercise 11.02: Applying SCSS to BEM

The aim of this exercise is to put writing SCSS in BEM markup into practice so that we can make our code even more maintainable. We'll use the HTML and CSS code we wrote in Exercise 11.01 as the basis to begin this exercise and then we'll rewrite the CSS so that it can be compiled from SCSS instead. Let's get started:

  1. Take a copy of Exercise 11.01.html and save this as Exercise 11.02.html in your Chapter11 project folder.
  2. Update the <title> and CSS link to the CSS file in the <head> of Exercise 11.02.html to point to the exercise2.css file that we'll compile in the following steps:

    <link href="css/exercise2.css" rel="stylesheet" />

  3. Create a new subfolder called scss and save the exercise2.scss file with the contents of css/exercise1.css inside it.
  4. Now, we'll modify exercise2.scss to convert the existing CSS into SCSS. The following is the resulting SCSS code:

    * {

        margin: 0;

        padding: 0;

    }

    body {

        font-family: Arial, sans-serif;

        font-size: 14px;

        color: #000;

    }

    .header {

      display: flex;

      align-items: center;

    }

    .logocontainer {

        flex: 0 0 auto;

        &__img {

            width: 100%;

            height: auto;

            display: block;

            border: 1px solid #000;

        }

    }

    .nav {

        &--header {

            flex: 1 1 auto;

            text-align: right;

            padding-right: 20px;

        }

        &--subnav {

            text-align: center;

            background: #000;

            padding: 10px 0;

        }

        &--footer {

            flex: 0 0 auto;

            text-align: right;

        }

        &__list {

            list-style: none;

        }

        &__item {

            display: inline-block;

            padding-right: 10px;

            &:after {

                content: '2022';

                padding-left: 10px;

            }

            &:last-child {

                padding-right: 0;

            }

            &:last-child:after {

                display: none;

            }

            .nav--subnav & {

                color: #FFF;

            }

        }

        &__link {

            color: #000;

            text-decoration: none;

            &:hover {

                text-decoration: underline;

            }

            .nav--subnav & {

                color: #FFF;

            }

        }

    }

    .article {

        margin: 20px;

        &__image {

            float: left;

            margin: 0 10px 10px 0;

            border: 1px solid #000;

            &--right {

                float: right;

                margin: 10px 0 0 10px;

            }

        }

    }

    .footer {

        background: #DDD;

        clear: both;

        display: flex;

        padding: 20px;

        &__copyright {

            flex: 1 1 auto;

        }

    }

    In the preceding SCSS code, inside every block are the elements and some modifier classes. This will create the same CSS output as exercise1.css does when it's compiled into exercise2.css. The original CSS file was 112 lines; we've written 109 lines of SCSS to replace it. When output into exercise2.css in a compressed output style, it's only 1 long line, which is super optimized for use on a production website. However, you've still got the SCSS file so that you can make edits, which makes this very maintainable.

  5. Now, we'll need to compile the SCSS, just as we did in Chapter 10, Preprocessors and Tooling. In the Chapter11 project folder, we'll need to add our package.json file with the following contents:

    {

      "name": "chapter11",

      "version": "1.0.0",

      "description": "HTML5 & CSS3 Workshop Chapter11 Exercises",

      "main": "index.js",

      "scripts": {

        "test": "echo "Error: no test specified" && exit 1",

        "scss": "node-sass --watch scss -o css --output-style compressed"

      },

      "author": "Matt Park",

      "license": "ISC",

      "dependencies": {

        "node-sass": "^4.12.0"

      }

    }

  6. Once this file is in place, we can navigate to the Chapter 11 folder in the Terminal and run the npm install command to ensure we've got the node-sass dependencies ready to compile next.
  7. Now, we're going to compile the exercise2.scss file by running our npm run scss command. This will output the contents of scss/exercise2.scss to css/exercise2.css upon saving the .scss file.
  8. Check the Exercise 11.02.html file in your web browser to check that the web page is still working as expected, as shown in the following screenshot:

Figure 11.6: Browser output

Now that we've completed this exercise, you should be able to write SCSS in the maintainable BEM markup standard and understand how CSS can be converted into nested SCSS and vice versa. In the next section of this chapter, we'll look at structuring our SCSS files into an even more maintainable format.

Structuring Your SCSS into Maintainable Files

In this section, we're going to explore how to make our SCSS more maintainable by splitting the code into separate files and folders, which is very useful when managing large code bases of CSS.

It is recommended to group SCSS rules together into blocks or components. For example, the navigation would have its own SCSS file, and all of those SCSS files would be merged into a single CSS file output when compiled.

Each individual SCSS file would have an underscore in front of the filename to prevent it from being individually compiled. This means we can create the _navigation.scss file and add our navigation styles to it. Inside our main file (main.scss), which is going to be output into CSS, we can list all the components we are going to import, like so:

/* Layout File */

@import '_header';

@import '_navigation';

@import '_footer';

With the example layout.scss file, this would output to layout.css, along with the contents of the _header, _navigation, and _footer SCSS files merged in.

It's good practice to ensure that the different types of SCSS code belong in their appropriate folder groups. We recommend using a file structure similar to the one shown in the following diagram:

Figure 11.7: Suggested basic layout for SCSS files and folders

As you can see, we have the following folders:

  • abstracts: This is where the SCSS files that don't output any CSS belong; for instance, variables, mixins, and other helper tools.
  • base: This is where the reset SCSS files and general "base" rules such as typography belong.
  • components: This is where the different components or modules live. This could be buttons, dropdowns, and other reusable components throughout the website.
  • layout: This is where key structural shared blocks are located; for example, the website header, navigation, and footer.

We also have main.scss, which is where all the mentioned folders would be imported. We can achieve this with a wildcard folder import so that as we add new files to the existing folders, they are imported without changing the main.scss file. See the suggested contents of main.scss in the following code, based on the folders in the preceding diagram :

@import "abstracts/_variables";

@import "abstracts/_mixins";

@import "base/_reset";

@import "base/_typography";

@import "components/_buttons";

@import "layout/_header";

@import "layout/_navigation";

@import "layout/_footer";

This code will get all the other SCSS code from these files and output via a single file called main.css.

Exercise 11.03: Using Structured SCSS Files

The aim of this exercise is to create SCSS file structures using a maintainable approach. We'll use the SCSS code we developed for Exercise 11.02 and split it into the appropriate files and folders in order to create a maintainable code base for the website to grow on. Let's get started:

  1. Take a copy of Exercise 11.02.html from your Chapter11 project folder and save it as Exercise 11.03.html.
  2. Update <title> and the CSS link to the CSS file in the <head> of Exercise 11.03.html to point to the exercise3.css file that we'll compile in the next step:

    <link href="css/exercise3.css" rel="stylesheet" />

  3. Save the scss/exercise3.scss file with the contents of scss/exercise2.scss inside it.
  4. Take a copy of the code from scss/exercise3.scss and create the following subfiles (note the new subfolders):

    scss/exercise3/base/_reset.scss:

    * {

        margin: 0;

        padding: 0;

    }

    scss/exercise3/base/_typography.scss:

    body {

        font-family: Arial, sans-serif;

        font-size: 14px;

        color: #000;

    }

    scss/exercise3/components/_article.scss:

    .article {

        margin: 20px;

        &__image {

            float: left;

            margin: 0 10px 10px 0;

            border: 1px solid #000;

            &--right {

                float: right;

                margin: 10px 0 0 10px;

            }

        }

    }

    scss/exercise3/layout/_header.scss:

    .header {

      display: flex;

      align-items: center;

    }

    .logocontainer {

        flex: 0 0 auto;

        &__img {

            width: 100%;

            height: auto;

            display: block;

            border: 1px solid #000;

        }

    }

    The scss/exercise3/layout/_navigation.scss code file can be found at https://packt.live/36XoXnB.

    scss/exercise3/layout/_footer.scss:

    .footer {

        background: #DDD;

        clear: both;

        display: flex;

        padding: 20px;

        &__copyright {

            flex: 1 1 auto;

        }

    }

  5. Now, we'll update the scss/exercise3.scss file with the following contents:

    @import 'exercise3/base/_reset';

    @import 'exercise3/base/_typography';

    @import 'exercise3/layout/_header';

    @import 'exercise3/layout/_navigation';

    @import 'exercise3/layout/_footer';

    @import 'exercise3/components/_article';

    This will import all the SCSS subfiles we just created.

  6. Now, we're going to compile the exercise3.scss file by running our npm run scss command. This will output the contents of scss/exercise3.scss to css/exercise3.css upon saving the .scss file.
  7. Check the Exercise 11.03.html file in the web browser at this point to check that the web page is still working as expected. This is shown in the following screenshot:

    Figure 11.8: Browser output

  8. Now, we're going to add a new SCSS file for variables so that we can create some color variables to use in our exercise web page. Create the following file:

    scss/exercise3/abstracts/_variables.scss

    $primary-color: #004275;

    $secondary-color: #ffd421;

    $tertiary-color: #00e1ea;

  9. We'll go through our SCSS files and replace the colors we've already defined for the new color variables, as follows:Replace any "#000" values for $primary-color variable Replace any "#FFF" values for $secondary-color variable Replace any "#DDD" values for $tertiary-color variable Save the files after you've made the changes.
  10. Now, we just need to add a new line to the top of scss/exercise3.scss and save the file:

    @import 'exercise3/abstracts/_variables';

    Note that it's very important to ensure that this is placed at the top of the scss/exercise3.scss file. This ensures that the variables are defined before we run the other SCSS code.

  11. Then, we're going to compile the exercise3.scss file again by running our npm run scss command and saving the .scss file to make it generate the CSS for css/exercise3.css.
  12. Check the Exercise 11.03.html file in the web browser again to ensure that the web page is still working as expected with the new color variables in use. This is shown in the following screenshot:

Figure 11.9: Browser output after new variable colors are added

We've now got a maintainable SCSS file structure with variables, reset styles, base typography styles, layout styles for the header, footer, navigation, and component styling for an article. This will be much more manageable as the website grows with components, pages, and styling rules. If we hadn't applied these best practices, it would be harder to manage the website project as it grows with more and more styles.

Since we can group the rules into components and different blocks, if we remove a certain component from the website in the future, cleaning up the styles would be as simple as removing the SCSS file for that component and removing the import line from the main SCSS file as well. This clean add/remove approach to new CSS files for blocks and components greatly reduces the amount of technical debt created over time as the project grows in size.

Good Practices for Maintainable CSS

There are several other good practices to follow in addition to using BEM with SCSS in structured folders and files. There are six points to consider when creating maintainable CSS:

  1. We can make use of the extend functionality in SCSS with the %class-name syntax. We can define a class for extending its use by using @extend class-name; in many places to save writing the same code again and again. See the following example in SCSS:

    %font-normal {

        font-family: Arial, sans-serf;

        font-size: 14px;

        color: #000;

    }

    body {

        @extend %font-normal;

        background: #CCC;

    }

    input[type=text] {

        @extend %font-normal;

        border: 1px solid #000;

    }

    This generates the following CSS:

    body,

    input[type=text] {

        font-family: Arial, sans-serf;

        font-size: 14px;

        color: #000

    }

    body {

        background: #CCC

    }

    input[type=text] {

        border: 1px solid #000

    }

    As you can see, wherever we use the extend class, it groups together and outputs in one go in the CSS. However, it's easier to maintain in SCSS as we still edit the code in its actual rule location, and so we don't have to create multiple rules for the same code – it's all handled upon the compilation of it.

  2. It's worth making sure you avoid "deep nesting," meaning that it shouldn't be necessary to nest more than three levels deep as this makes it much harder to override styles in the code, thus reducing its maintainability. Not only this, but longer CSS rule selectors have a performance hit in rendering the CSS.
  3. We should always remain consistent with using quotation marks in our SCSS (and CSS) and not mixing between single and dark quotation marks. When using SCSS, it's preferred to use single quotation marks, but the important point of ensuring consistency and maintainability is to not use both in your SCSS files.
  4. Our SCSS rules should follow a sensible order so that they can easily be located by another developer or even yourself a few days later. They should follow a logical order while we're using BEM since we can store our SCSS in an appropriate subfolder to help group rules in logical places. However, within each file, we can order our rules in a way that just makes sense to read. Within our SCSS selectors, we can also group our properties together logically. For example, width, height, margin, and padding can be underneath each other. Typography-related properties can be grouped together (for instance, font-size, color, and font-family). Take a look at the following example code. You can see that the properties are randomly ordered:

    .unordered-selector {

        width: 100px;

        font-family: Arial;

        background: black;

        color: white;

        padding: 5px;

        text-decoration: underline;

        height: 100px;

        border: 1px solid white;

        font-size: 20px;

    }

    With the following ordered example, you can see that the properties follow a grouping order, that is, of the type of properties, thus resulting in more maintainable CSS:

    .ordered-selector {

        width: 100px;

        height: 100px;

        padding: 5px;

        font-family: Arial;

        font-size: 20px;

        color: white;

        text-decoration: underline;

        background: black;

        border: 1px solid white;

    }

  5. It's worth understanding when we should use the !important flag in CSS. The short answer is, very rarely. Let's understand why:

    When CSS gets out of control with the deep nesting of rules (for instance, beyond three nesting levels deep), it's often very easy for a new developer to come into the website project and add an !important flag onto the end of various CSS properties so that they can use a shorter CSS selector (for instance, one or two nesting levels deep) in order to override a value with something else.

    You can imagine that, after a while, this becomes very messy, and soon becomes difficult to maintain, with various CSS selectors trying to override each other with the !important flag. Use this very sparingly to avoid a maintenance disaster.

  6. Avoid using ID CSS selectors with your styling rules. These are mainly used in JavaScript and are too specific and not reusable. You should use BEM classes in your CSS instead of IDs to make the CSS more identifiable, reusable, and maintainable.

We've now covered various aspects of writing maintainable CSS, including understanding what is meant by the phrase semantic CSS, writing CSS, SCSS with the BEM approach, understanding componentization and rule grouping, writing maintainable SCSS with sensible file and folder structures, and finally, following good CSS practices to generally create more maintainable code. We'll now look at applying our knowledge of maintainable CSS to our activity. We'll do this by updating our video store home page with the new techniques we've learned about.

Activity 11.01: Making Our Video Store Web Page Maintainable

The aim of this activity is to take our existing video store home page (from Chapter 10, Preprocessors and Tooling, Activity 10.01, Converting a Video Store Home Page into SCSS) and refactor the code so that it uses BEM semantic markup with suitable SCSS file structuring to create a more maintainable web page. Let's get started:

  1. Take a copy of the Chapter 10, Preprocessors and Tooling, Activity 10.01, Converting a Video Store Home Page into SCSS, HTML file and save it in your Chapter11 project folder under Activity 11.01.html.
  2. Take a copy of Chapter 10, Preprocessors and Tooling, Activity 10.01, Converting a Video Store Home Page into SCSS, SCSS file and save it in your Chapter11 project folder under scss/activity1.scss.
  3. Edit your Activity 11.01.html file so that it uses BEM semantic markup.
  4. Edit your activity1.scss to follow the updated BEM semantic markup.
  5. Split the activity1.scss file's SCSS code into suitable subfolders and files, and then import these into the activity1.scss file.
  6. Compile the SCSS in your Terminal in order to compile your activity1.css file.
  7. Test the web page in your browser to ensure it's loading as expected, as shown in the following screenshot:

Figure 11.10: Browser output on mobile and desktop

Note

The complete solution can be found in page 616.

Summary

In this chapter, we covered various aspects of creating and using maintainable CSS in our work. First, we got BEM markup for our HTML and CSS and then we looked at how SCSS can work with BEM and how to separate its folders and files to enable better CSS codebase management at a larger scale. We also reviewed additional good practices to help us write maintainable CSS. You should now have an idea of what maintainable CSS code looks like and how you can write your CSS to follow the same standards.

In the next chapter of this book, we will learn about web components and how APIs, when combined, can create powerful features on a web page.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset