⇦ Home

Zero runtime CSS-in-JS : Is this where great DX meets top-notch Web Performance?

19th Nov, 2021
A few weeks ago, a client team asked for my inputs on the performance impact of the styled-components library. They were already using styled-components for one of their website frontends. But, as they were about to build a different frontend (for a different website), they wanted to evaluate if styled-components was the right choice in the ever-evolving frontend ecosystem.

This was a novel task for me. As a frontend speed & scalability guy, I often get involved with the websites when their frontend choices & setup are long in place. And often, my first job is to find the solutions living within the constraints of those choices. But, here, I had to provide inputs to help make that choice. 😊

How I feel when starting a speed optimization assigment!

How I feel when starting a speed optimization assigment!

Background : CSS-in-JS, DX and Web Performance

Before I talk about the findings from the exercise, here’s a quick brief on the friction in the web development world with respect to CSS-in-JS, good developer experience (DX) and web performance.

CSS-in-JS and Web Performance


Modern UI frameworks have components as the basic unit of the frontend code. This allows us to build large and maintanable web applications. But, regular CSS doesn’t directly fit into this component centric model. Writing maintainable CSS that can fit well here requires us to follow methodologies like OOCSS (Object oriented CSS) and a lot of consistent discipline.

CSS-in-JS libraries like styled-components and emotion solve this by enabling us to write component-centric styling. Having the styling code closely tied to the component JavaScript enables dynamic styling and easier maintenance. This, in-turn, results in an improved DX.

But, making the UI styling JavaScript driven also means we make it JavaScript dependent at runtime. This has performance implications:

As a result of this, all the DX goodness of CSS-in-JS and top-notch web performance appear like an either-or.

Speed Impact of styled-components

So, what is the speed impact of using CSS-in-JS? To measure this, I created two versions of the below page (with NextJS) - one version styled via CSS modules and another with styled-components.

And, below are the measured performance numbers:

Measured via WebPageTest : Fast 3G | Moto G4 | US-East-1

Measured via WebPageTest : Fast 3G | Moto G4 | US-East-1


Measured via Chrome devtools (Network tab)

Measured via Chrome devtools (Network tab)


Measured via Chrome devtools (Performance tab) during page re-rendering

Measured via Chrome devtools (Performance tab) during page re-rendering


Based on the above:

Enter Zero Runtime CSS-in-JS

I then decided to evaluate zero runtime CSS-in-JS. More specifically, I evaluated linaria and studied astroturf.

These are CSS-in-JS libraries so we get to write our styling within the component files. They extract the CSS into separate CSS files during the build process. They do not require runtime JavaScript execution for styling. These libraries achieve dynamic props based styling via CSS variables at runtime.

So, I created a linaria styled version of the same page used for benchmark. This gave an opportunity to compare how similar it’s styling is to styled-components:

const Button = styled.button`
  border-radius: 3px;
  margin: 0.5em 1em;
  padding: 0.25em 1em;
  ${props => props.primary 
  && props.color && css`
    background: ${props.color};
    border: 2px solid ${props.color};
    color: white;
  `}
  ${props => !props.primary 
  && props.color && css`
  background: transparent;
  border: 2px solid ${props.color};
  color: ${props.color};
`}
`;
Styling CSS with styled-components
const Button = styled.button`
  border-radius: 3px;
  margin: 0.5em 1em;
  padding: 0.25em 1em;
  background: ${props => 
    (props.primary ? props.color : 
        'transparent')};
  color: ${props => 
    (props.primary ? 'white' : 
        props.color)};
  border-width: 2px;
  border-style: solid;
  border-color: ${props => 
    (props.color)};
`;
Styling CSS with linaria

Unrelated to performance, but something of paramount importance - linaria’s similarity can make it’s adoption easier and future migrations simpler. However, I’m not sure if other zero runtime CSS-in-JS libraries are as similar to styled-components as linaria.

Speed Comparison : CSS modules vs styled-components vs linaria

So, how does the linaria styled version of the same page perform compare to the other versions? Below are the performance numbers:

Measured via WebPageTest : Fast 3G | Moto G4 | US-East-1

Measured via WebPageTest : Fast 3G | Moto G4 | US-East-1


Measured via Chrome devtools (Network tab)

Measured via Chrome devtools (Network tab)


Measured via Chrome devtools (Performance tab) during Page Re-rendering

Measured via Chrome devtools (Performance tab) during Page Re-rendering


Based on the above charts:

Conclusion

Based on the undertaken benchmarks and having written (very limited) linaria styling, my findings from this exercise were as following:

Based on the above findings, we decided to undertake a more detailed evaluation of linaria. To do so, we plan to style a few components and pages for the new website with linaria. During this process, we plan to check on the following aspects:


Note : Source code for the benchmark used to derive the results shared above is located here.

You can follow me on my twitter where I tweet about my entrepreneurship journey, site speed and web dev experiences.