In the summer of 2015, we released a new version of auctionata.com. We built it with the following stack:

  • Node.js
  • React.js
  • SCSS

One particular story I want to share is how we evolve our CSS styles since the initial launch.

The bug

Yes, this is true. Our original version of the CSS file weighted 1 Mb, and it was obviously a bug. We are using the component-based approach for our front end. We define styles for the component in the separate file and then import it into component’s source file:

Each .scss file contains the import of the setup.scss, where we declare our global variables, mixins and other shared code:

The problem was that _fonts.scss included a declaration of 2 custom font-face declarations like this:

During a build process, all fonts files were embedded not once but for each component we use on the home page. This way out of 1 Mb 99% contained duplicated fonts. The fix was obvious, we moved font-face declarations out of _fonts.scss and imported it once in the root container. As a result, our CSS file shrank to 100 Kb.

WOFF only

A 10x improvement was impressive, but 100 Kb of CSS still seemed too much. Furthermore, style declaration blocked rendering until the file was loaded and parsed in all browsers. So having the will to decrease the size of CSS even further I started to explore.

Auctionata is the leading online auction house for art and luxury collectibles. Our customer base is mostly using modern versions of the browsers. As a consequence, we support two last versions of the major browsers (Chrome, Firefox, Safari, IE, Edge). Luckily, WOFF format has great support in the browsers:

With that said we left only WOFF format and the result CSS was reduced by 33% to more appropriate 65 Kb.

Loading fonts asynchronously

Let’s take a step aside and review our assumptions why we started with embedding fonts into stylesheet file initially. What issues would we have if fonts are loaded separately? A good explanation of the problem called FOIT (flash of invisible text) I found in the article “How we use web fonts responsibly, or, avoiding a @font-face-palm” written by Zach Leatherman.

When you reference an external web font using @font-face, most browsers will make any text that uses that font completely invisible while the external font is loading.

On the same blog, I’ve found a fantastic article “Font Loading Revisited with Font Events” by Scott Jehl devoted to the exact problem I was trying to solve. I briefly highlight the suggested approach:

  • Load fonts async using FontFaceObserver written by Bram Stein.
  • As soon as fonts are loaded apply a fonts-loaded class to the body.
  • Rewrite styles to use fallback fonts initially and custom fonts when a fonts-loaded class is available.
  • Cache fonts locally.
  • Use cookies to apply a fonts-loaded class on the server.

The biggest challenge was to rewrite of the existing styles. It wasn’t an enjoyable process, but a reward was worth it.

In the end, our CSS file was decreased one more time to 20 Kb. As a result of the refactoring, we disabled embedding of the fonts. It opened the room for one more improvement: we started to serve WOFF2 format again which has support in the latest version of Firefox and Chrome. Normally, it has 30% less file size.

Conclusion

Although we made 50 times an improvement in comparison to the initial version, we are not close to the end. Google Page Insights still complains that our CSS file blocks rendering of the page. My favorite choice at the moment would be to extract and inline above the fold CSS using a Critical library authored by Addy Osmani and load main CSS asynchronously with JavaScript.

By this example, I want to highlight the process of continuous improvement that could be applied to any field of your everyday activities. It is a good habit to challenge the initial assumptions, most of the time we should regularly review them.