Optimize web page performance: CSS

    Nowadays, the speed of the Internet is quite high. It would seem that we can forget about those times when we had to wait 20-30 (or even more) seconds for the web page to load and display on the screen - now we are waiting for the page to render on average about one to two seconds. However, do not forget that a significant part of users visit your site from mobile devices on which communication is not always stable. In this regard, it will not be out of place to pay a little attention to optimizing your code.

    This article will discuss various methods for optimizing style sheets. I’ll talk about what affects the page rendering speed, how to make the browser render the page faster and what tools to use for optimization.

    How the page is displayed


    Let's figure out what happens when you open a new page.

    So, you press enter and the browser sends a request to the server. In response, the server sends the requested page.

    1. The browser analyzes the resulting markup. Nodes are formed, from which the DOM is then built.
    2. If the browser detects links to style sheets, it immediately sends a request to the server and uploads the files; at the same time, rendering of the page is blocked.
    3. After loading the styles, the browser analyzes them and builds CSSOM.
    4. When the DOM and CSSOM are formed, the browser creates a rendering tree based on them. Only those elements that will be displayed on the screen fall into it.
    5. For each element from the visualization model, its position on the page is calculated. This process is called layout .
    6. After the completion of the layout, the browser draws the result (painting).

    You can tell a lot about the page rendering process, but in the context of this article we are interested in the second point.

    To begin with, I repeat: the browser blocks the rendering of the page during loading and processing style sheets. If several css files are connected to the page, then the browser will download everything, regardless of media queries. Fortunately, modern browsers are smart enough to primarily download the files that are directly required to render the main part of the page. Let's look at the following example:

    <linkhref="style.css"><linkhref="style.css"media="screen"><linkhref="style.css"media="(orientation: portrait)"><linkhref="style.css"media="(max-width: 960px)"><linkhref="style.css"media="print">

    The link to the first file of the stylesheet has no attributes, and the browser will begin to download the file immediately after the link to it is detected. The link to the second file has an attribute media="screen". The browser assigns this attribute to the element <link>by default if it is absent, so the second file will be processed immediately after the first. Links to the third and fourth files contain a conditional media-request. If this condition is met, the browser will begin processing the file. If it is not executed, the browser will postpone these files “for later”, and first process more relevant styles. The fourth link in the media attribute is “print”, indicating to the browser that this file contains print styles. Since the browser does not need them at the moment, it will also delay their processing.

    Optimization methods


    We figured out the order of processing styles, now it's up to you to take this into your arsenal. Next, we will talk about methods for optimizing the stages of rendering a page (loading, processing styles).

    Using High Performance Selectors


    Do not forget that different selectors are processed by the browser at different speeds. Steve Sowders once conducted research and sorted CSS selectors by performance - from the fastest to the slowest:

    • Identifier: #id
    • Grade: .class
    • Element: div
    • Neighboring Element: h2 + p
    • Child element: li > ul
    • Nested Element: ul li
    • General selector: *
    • Attribute: [type = "email"]
    • Pseudo-classes / pseudo-elements: a:hover

    It is highly discouraged to use a common selector *for anything. By the way, the gain when using an identifier instead of a class is actually quite small, so you can use whatever is more convenient for you.

    Cascade reduction


    A large cascade adversely affects performance. Compare the two designs:

    #header.header__innernavul.nav-menuli:hovera {}
    #headerli:hovera {}
    

    Obviously, the second design will be processed faster.

    I cannot but mention one important point. The browser processes selectors from right to left. Consider the following construction:

    .sociallia {}
    

    In this case, the browser will first find all the links on the page (just imagine how long it will take to process such a request on huge pages), then it will select the links embedded in <li>, from the received links it will filter out everything that is not embedded in the element with the class .social. I recommend in such cases to reduce the design to two selectors of the following type:

    .social.social_link {}
    


    This approach is better because we reduced the cascade to a minimum and replaced the selectors with more efficient ones.

    CSS minification and gluing


    Avoid using many small CSS files; It’s good practice to “glue” all files. Thanks to gluing files, the browser will have to make one request to the server instead of several.

    Also, do not forget about file minification. Usually there is a lot of garbage in the code in the form of comments (do not throw tomatoes, this is garbage for the browser, not for the developer). There are many different tools for compressing and minifying style sheets. I will give some of them:


    Disabling: hover states when scrolling a page


    Some sites abound with interactive elements that have unique: hover states. When the user scrolls the page, he is unlikely to be interested in what will happen if you hover over that button or this input field. You can safely disable: hover states when scrolling.

    A simple solution is to create a class .disable-hoverand add it to <body>while scrolling.

    .disable-hover {
      pointer-events: none;
    }
    

    var body = document.body,
        timer;
    window.addEventListener('scroll', function() {
      clearTimeout(timer);
      if(!body.classList.contains('disable-hover')) {
        body.classList.add('disable-hover')
      }
      timer = setTimeout(function(){
        body.classList.remove('disable-hover')
      }, 500);
    }, false);
    

    Critical-path CSS


    As you already learned from the beginning of the article, styles connected through <link>block the page from rendering until it is fully loaded. If the style sheet is large, then mobile device users will experience a significant delay before something appears on the page. In other words, the page will be completely blank until the styles load.

    To avoid this, a technique was invented that made it possible to display part of the content even before the styles were fully loaded. It is applied as follows. Look at the desktop and mobile versions of the site and determine which parts of the page are critical to the user. Choose the CSS that stylizes these parts, minify it and place it inline before connecting the main styles. An inline view means a description of the styles directly on the page itself, inside the tag <style>.

    Finding critical CSS is a tedious task for many. Fortunately, there have long been tools to automate this process.


    Conclusion


    Hope this article has been helpful to you. I would be glad if in the comments you describe your techniques for optimizing CSS. Thank you for reading!

    Also popular now: