written by PrimeHammer

The performance of styled React components

joe-neric-223562.small

Introduction

Styling React components has always been a very discussed theme. Since the first release of React, hundreds of packages taking care of our styles have been published.

You may ask which one has the fastest scripting time, render time or which one is the smallest and that is exactly what I will try to answer in this article.

I will take a look at the performance and production build sizes of some of the most known libraries helping us with styles in React: styled-components, radium, glamorous and sass, css in js and inline styles. At the first look, the main difference between those is the way you can write styled components, but that would be a different story. This story is mostly about numbers.

Package size

One of the first tests I created is focused on the package size. The smaller the package is, the less data is transferred to the client and thus the app may load faster.

Importing packages one by one to calculate their build size.

In order to obtain particular package size for every library, I’ve used the default webpack configuration from the create-react-app boilerplate project. Production build size of the default (empty) project was 157.40kb. Next, I’ve introduced styling package, by importing it into the project, created the production build and subtracted the final size from the size of the empty build obtained earlier. This process was repeated for every library.

The compressed size has been calculated the same way, but the build has been compressed using the default configuration of 7-zip. There are many other ways you can compress your files and the numbers may vary on the used configuration. Glamorous uses glamor as a peer dependency and does not work without installing this package.
The compressed size has been calculated the same way, but the build has been compressed using the default configuration of 7-zip. There are many other ways you can compress your files and the numbers may vary on the used configuration.
Glamorous uses glamor as a peer dependency and does not work without installing this package.

However, package size is usually not the most important thing as we can cache the source files with service-worker to reduce the amount of transferred data and even make our page accessible while offline! A more important thing may be the real performance. Let’s take a look at the render performance of our libraries and the impact on UX.

Render performance

This test is focused on measuring the time from when the page download starts to when our visitors can interact with the website. When the page source is loaded, web browsers run the included scripts in order to make the content visible. The faster the content appears, the sooner can our visitor interact with our website.

Before I start testing I need to create some testing environment. The tests will run on a simple HTML file which may look like this one.htmlexample

I have created 4 different components for each library. They will be rendered in a big table containing 10 000 rows, where each row includes those components. The rendered elements are: div, span, text input, and button. To get the best results those components need to have a lot of styles. The styled elements are not very eye friendly, but they are perfect for our tests.

Similar styles have been used in every test case.

Snímek obrazovky 2017-09-27 v 14.49.02

When we create the final build using webpack, we can start testing our application.

To test the application we will just let the browser render the large table and measure different aspects of rendering. To reduce the deviation, we will run every test at least 100 times for every package.

Render time and time to First meaningful paint

The following chart shows the time required to render the table – Render time and the time to First meaningful paint.

Technical notes - First meaningful paint (time when page’s content appeared on the screen) has been calculated with lighthouse while rendering large table on chrome (v 60). - Render time has been calculated using componentWillMount and componentDidMount while rendering the same table.
Technical notes
– First meaningful paint (time when page’s content appeared on the screen) has been calculated with lighthouse while rendering large table on chrome (v 60).
– Render time has been calculated using componentWillMount and componentDidMount while rendering the same table.

When you are testing the performance of your React application, make sure to test the First meaningful paint using lighthouse as it will give you different numbers as you would get when measuring the time using just React events (componentDidMount and componentWillMount). Why ? Because First meaningful paint will give you numbers when something appeared on the page (from blank screen to some content). Basically when styles have been used on the layout. React events can only measure the time when layouts/styles are being calculated.

In this chart you can see that CSS and SASS preprocessor, Glamorous and Styled-components have very good results, but why have the inline styles much bigger time to the First meaningful paint than glamorous, even though both of them use styles from the object?

Glamorous actually uses styles defined by the object only once and then creates css classes, which are then used to style elements, because they are much faster than styles from objects.

You may ask why is the time to First meaningful paint and render time of css and sass almost the same (even though the sass files are sometimes larger because of variables, if statements, loops, …). Every css preprocessor works almost the same way. The variables and if statements and other cool features are replaced at the build time and at the end they usually look exactly the same.

Inline styles have problems

With inline styles, you can feel like you can save a lot of space because they basically require no library. The problems with inline styles will appear later in your project and you will not like writing HOC (High-Order Components) to support the sweet parts of CSS like focus, hover, animations, media queries, etc…

But there are solutions

A  very popular package is, for example, Radium, which basically adds the missing features of inline styles: pseudo-classes, media queries and so on. It’s a pretty mature library and they recently added the server-side rendering support. You can check the example here or if you are experiencing performance issues, you can discuss at their github page.

If you would like to read more about the performance, pros and cons of inline styles, you can check this article or if you are more interested in speeding up your code, don’t miss this article about prepack in production.

Test it by yourself

If you want to run the tests on your machine, you can download the full code on https://github.com/MichalSzorad/styling-react. You can follow the guide in README.md in order to get the tests done.

Conclusion

There you go, I have tested the most popular React styling libraries. Even though the render time and bundle size may vary on different packages, each package has its own pros and cons.

If your priority is the speed, glamorous or styled-components is exactly what you could use in your web apps. Writing styles in strings for styled-components may be something unusual, but the visitors will appreciate the fast loaded web page. If you decide to use styled-components, do not forget to install plugin to support syntax highlighting in strings or maybe help creating a new one.

Sass/css and inline styles are also pretty fast, but if you decide to reuse your code for your React Native app be prepared to rewrite your stylesheets. (Or you can try the css-to-react-native package, which may work for most of the styles.) But on the other hand, css and other style preprocessors are a good choice for web applications.

  • 67
    Shares
  • Great article, guys. CSS-in-JS is cool but the future owns CSS-FROM-JS, see our Linaria https://blog.callstack.io/zero-runtime-css-from-js-with-linaria-443d8a6834ce 🤓 😂

    • Michal Szorad

      Hi @jukben:disqus , thanks for the feedback. I really appreciate that. Linaria looks awesome! I like the way, you can use js expressions inside the css template, without losing the ability to create the css file at the build time. I will give it a try one day 😉

  • Pingback: Benchmark of styling solutions for React – Full-Stack Feed()

  • Vytautas Butkus

    Or you could always use PostCSS with all the modern and upcoming CSS features, without caring for any performance impacts whatsoever or caring even caring for ugly abstractions hidden behind non standard css syntax…

  • Pol Guixé

    Have you tested JSS?