11 min read

Loosely put, website optimization refers to the activities and processes that improve your website’s user experience and visibility while reducing the costs associated with hosting your website.

In this article, we will learn tips and techniques for client-side optimization.

This article is an excerpt from Mastering Bootstrap 4 – Second Edition by Benjamin Jakobus, and Jason Marah. In this book, you will learn to build a customized Bootstrap website from scratch, optimize your website and integrate it with third-party frameworks.

CSS optimization

Before we even consider compression, minification, and file concatenation, we should think about the ways in which we can simplify and optimize our existing style sheet without using third-party tools. Of course, we should have striven for an optimal style sheet, to begin with, and in many aspects we did. However, our style sheet still leaves room for improvement.

Inline styles are bad

After reading this article, if you only remember one thing, then let it be that inline styles are bad. Period.

Avoid using them whenever possible. Why? That’s because not only will they make your website impossible to maintain as the website grows, they also take up precious bytes as they force you to repeat the same rules over and over. Consider the following code piece:

   <div class="carousel-inner" role="listbox">
    <div style="height: 400px" class="carousel-item active">
      <img class="d-block img-fluid" src="images/brazil.png" 
      data-modal-picture="#carousel-modal">
      <div class="carousel-caption">
        Brazil
      </div>
    </div>
    <div style="height: 400px" class="carousel-item">
      <img class="d-block img-fluid" src="images/datsun.png" 
      data-modal-picture="#carousel-modal">
      <div class="carousel-caption">
        Datsun 260Z
      </div>
    </div>
    <div style="height: 400px" class="carousel-item">
      <img class="d-block img-fluid" src="images/skydive.png" 
      data-modal-picture="#carousel-modal">
      <div class="carousel-caption">
        Skydive
      </div>
    </div>
   </div>

Note how the rule for defining an item’s height, style="height: 400px", is repeated three times, once for each of the three items. That’s an additional 21 characters (or 21 bytes, assuming that our document is UTF-8) for each additional image. Multiplying 3*21 gives us 63 bytes, and 21 more bytes for every new image that you want to add. Not to mention that if you ever want to update the height of the images, you will need to manually update the style attribute for every single image. The solution is, of course, to replace the inline styles with an appropriate class. Let’s go ahead and define an img class that can be applied to any carousel image:

    .carousel-item { 
        height: 400px; 
    }

Now let’s go ahead and remove the style rules:

    <div class="carousel-inner" role="listbox">
      <div style="height: 400px" class="carousel-item active">
        <img class="d-block img-fluid" src="images/brazil.png" 
        data-modal-picture="#carousel-modal">
        <div class="carousel-caption">
          Brazil
        </div>
      </div>
      <div style="height: 400px" class="carousel-item">
        <img class="d-block img-fluid" src="images/datsun.png" 
        data-modal-picture="#carousel-modal">
        <div class="carousel-caption">
          Datsun 260Z
        </div>
      </div>
      <div style="height: 400px" class="carousel-item">
        <img class="d-block img-fluid" src="images/skydive.png" 
        data-modal-picture="#carousel-modal">
        <div class="carousel-caption">
          Skydive
        </div>
      </div>
    </div>

That’s great! Not only is our CSS now easier to maintain, but we also shaved 29 bytes off our website (the original inline styles required 63 bytes; our new class definition, however, requires only 34 bytes). Yes, this does not seem like much, especially in the world of high-speed broadband, but remember that your website will grow and every byte adds up.

Avoid Long identifiers and class names

The longer your strings, the larger your files. It’s a no-brainer. As such, long identifier and class names naturally increase the size of your web page. Of course, extremely short class or identifier names tend to lack meaning and therefore will make it more difficult (if not impossible) to maintain your page. As such, one should strive for an ideal balance between length and expressiveness. Of course, even better than shortening identifiers is removing them altogether. One handy technique of removing these is to use hierarchical selection. Have a look at an events pagination code piece. For example, we are using the services-events-content identifier within our pagination logic, as follows:

    $('#services-events-pagination').bootpag({ 
        total: 10 
        }).on("page", function(event, num){ 
            $('#services-events-content div').hide(); 
            var current_page = '#page-' + num; 
            $(current_page).show(); 
    });

To denote the services content, we broke the name of our identifier into three parts, namely, services, events, and content. Our markup is as follows:

    <div id="services-events-content"> 
        <div id="page-1"> 
            <h3>My Sample Event #1</h3> 
            ... 
        </div> 
    </div>

Let’s try and get rid of this identifier altogether by observing two characteristics of our Events section:

  • The services-events-content is an indirect descendent of a div with the id services-events. We cannot remove this id as it is required for the menu to work.
  • The element with the id services-events-content is itself a div. If we were to remove its id, we could also remove the entire div.

As such, we do not need a second identifier to select the pages that we wish to hide. Instead, all that we need to do is select the div within the div that is within the div that is assigned the id services-events. How do we express this as a CSS selector? It’s easy—use #services-events div div div. Also, as such, our pagination logic is updated as follows:

    $('#services-events-pagination').bootpag({ 
        total: 10 
    }).on("page", function(event, num){ 
        $('#services-events div div div').hide(); 
        var current_page = '#page-' + num; 
        $(current_page).show(); 
    });

Now, save and refresh. What’s that? As you clicked on a page, the pagination control disappeared; that’s because we are now hiding all div elements that are two div elements down from the element with the id services-events. Move the pagination control div outside its parent element. Our markup should now look as follows:

<div role="tabpanel" class="tab-pane active" id="services-events">
            <div class="container">
              <div class="row">
                  <div id="page-1">
                    <h3>My Sample Event #1</h3>
<h3>My Sample Event #2</h3>

</div>
<div id="page-2">
<h3>My Sample Event #3</h3>

</div>
</div>
<div id="services-events-pagination"></div>
</div>
</div>

Now save and refresh. That’s better! Last but not least, let’s update the css. Take the following code into consideration:

    #services-events-content div { 
        display: none; 
    } 
    #services-events-content div img { 
        margin-top: 0.5em; 
       margin-right: 1em; 
    } 
    #services-events-content { 
        height: 15em; 
        overflow-y: scroll; 
    }

Replace this code with the following:

    #services-events div div div { 
        display: none; 
    } 
    #services-events div div div img { 
        margin-top: 0.5em; 
        margin-right: 1em; 
    } 
    #services-events div div div { 
        height: 15em; 
        overflow-y: scroll; 
    }

That’s it, we have simplified our style sheet and saved some bytes in the process! However, we have not really improved the performance of our selector. jQuery executes selectors from right to left, hence executing the last selector first. In this example, jQuery will first scan the complete DOM to discover all div elements (last selector executed first) and then apply a filter to return only those elements that are div, with a div parent, and then select only the ones with ID services-events as parent. While we can’t really improve the performance of the selector in this case, we can still simplify our code further by adding a class to each page:

<div id="page-1" class="page">...</div> 
<div id="page-2" class="page">...</div> 
<div id="page-3" class="page">...</div>

Then, all we need to do is select by the given class: $('#services-events div.page').hide();.
Alternatively, knowing that this is equal to the DOM element within the .on callback, we can do the following in order to prevent us from iterating through the whole DOM: $(this).parents('#services-vents').find('.page').hide();

The final code will look as follows:

$('#services-events-pagination').bootpag({
    total: 10
}).on("page", function(event, num) {
   $(this).parents('#services-events').find('.page').hide();
   $('#page-' + num).show();
});

Note a micro-optimization in the preceding code—there was no need for us to create that var in memory. Hence, the last line changes to $('#page-' + num).show();.

Use Shorthand rules when possible

According to the Mozilla Developer Network (shorthand properties, Mozilla Developer Network, https://developer.mozilla.org/en-US/docs/Web/CSS/Shorthand_properties, accessed November 2015), shorthand properties are:

“CSS properties that let you set the values of several other CSS properties simultaneously. Using a shorthand property, a Web developer can write more concise and often more readable style sheets, saving time and energy.”                                                                                    – Mozilla Developer Network, 2015

Unless strictly necessary, we should never be using longhand rules. When possible, shorthand rules are always the preferred option. Besides the obvious advantage of saving precious bytes, shorthand rules also help increase your style sheet’s maintainability. For example, border: 20px dotted #FFF is equivalent to three separate rules:

    border-style: dotted;
    border-width: 20px;
    border-color: #FFF; 

Group selectors

Organizing selectors into groups will arguably also save some bytes.

    .navbar-myphoto .dropdown-menu > a:hover {
        color: gray;
        background-color: #504747;
    }
    .navbar-myphoto .dropdown-menu > a:focus {
        color: gray;
        background-color: #504747;
    }
    .navbar-myphoto .dropdown-menu > .active > a:focus {
        color: gray;
        background-color: #504747;
    }

Note how each of the three selectors contains the same declarations, that is, the color and background-color properties are set to the exact same values for each selector. To prevent us from repeating these declarations, we should simply group them (reducing the code from 274 characters to 181 characters):

    .navbar-myphoto .dropdown-menu > a:hover,
    .navbar-myphoto .dropdown-menu > a:focus,
    .navbar-myphoto .dropdown-menu > .active > a:focus {
        color: gray;
        background-color: #504747;
    }

Voilà! We just saved 93 bytes! (assuming UTF-8 encoding).

Rendering times

When optimizing your style rules, the number of bytes should not be your only concern. In fact, it comes secondary to the rendering time of your web page. CSS rules affect the amount of work that is required by the browser to render your page. As such, some rules are more expensive than others. For example, changing the color of an element is cheaper than changing its margin. The reason for this is that a change in color only requires your browser to draw the new pixels. While drawing itself is by no means a cheap operation, changing the margin of an element requires much more effort. Your browser needs to both recalculate the page layout and also draw the changes. Optimizing your page’s rendering times is a complex topic, and as such is beyond the scope of this post.

However, we recommend that you take a look at http://csstriggers.com/. This site provides a concise overview of the costs involved when updating a given CSS property.

Minifying CSS and JavaScript

Now it is time to look into minification. Minification is the process of removing redundant characters from a file without altering the actual information contained within it. In other words, minifying the css file will reduce its overall size, while leaving the actual CSS style rules intact. This is achieved by stripping out any whitespace characters within our file. Stripping out whitespace characters has the obvious result that our CSS is now practically unreadable and impossible to maintain. As such, minified style sheets should only be used when serving a page (that is, during production), and not during development.

Clearly, minifying your style sheet manually would be an incredibly time-consuming (and hence pointless) task. Therefore, there exist many tools that will do the job for us. One such tool is npm minifier. Visit https://www.npmjs.com/package/minifier for more.

Let’s go ahead and install it:

    sudo npm install -g minifier

Once installed, we can minify our style sheet by typing the following command:

    minify path-to-myphoto.css

Here, path-to-myphoto.css represents the path to the MyPhoto style sheet. Go ahead and execute the command. Once minification is complete, you should see the Minification complete message. A new CSS file (myphoto.min.css) will have been created inside the directory containing the myphoto.css file. The new file should be 2,465 bytes. Our original myphoto.css file is 3,073 bytes. Minifying our style sheet just reduced the number of bytes to send by roughly 19%!

We touched upon the basics of website optimization and testing. In the follow-up article, we will see how to use the build tool Grunt to automate the more common and mundane optimization tasks.

To build responsive, dynamic, and mobile-first applications on the web with Bootstrap 4, check out this book  Mastering Bootstrap 4 – Second Edition.

Read Next:

Get ready for Bootstrap v4.1; Web developers to strap up their boots

How to use Bootstrap grid system for responsive website design?

Bootstrap 4 Objects, Components, Flexbox, and Layout

Content Marketing Editor at Packt Hub. I blog about new and upcoming tech trends ranging from Data science, Web development, Programming, Cloud & Networking, IoT, Security and Game development.

LEAVE A REPLY

Please enter your comment!
Please enter your name here