CSS-in-JS, One Step Forwards, One Step Sideways, or One Step Back

We have had an evolution in CSS over the past few years with the advent of CSS-in-JS. To many it has felt like a breath of fresh air, and the next logical step after JSX brought HTML into JS. But now that it has been popular for awhile, maybe the honeymoon phase is over and we can take a critical look at the benefits and downsides.

CSS-in-JS Pros

Improved Developer Ergonomics. CSS-in-JS brings the full power of JavaScript to CSS. Frontend developers who are already very comfortable and familiar with JavaScript can use it to manipulate conditional styling and build abstractions around styling.

Colocation, all-for-one, one-for-all. HTML has already been brought to JS through JSX. Why not bring CSS there as well? One component and file can contain all necessary markup, presentation, and logic.

Faster build times. Sass compilation is slow. And so are tools that need a pre- or post-processing step applied to CSS. CSS-in-JS hooks into all the existing JS build tooling that allows for fast refreshing in the browser to quickly iterate.

Build tooling. Many tools have arose around CSS-in-JS that perform linting, static analysis, TypeScript integration, deduplication, atomization -- the list grows each day.

Eliminates the Cascade. Rather than needing to adhere to CSS methodologies like BEM, CSS-in-JS takes care of providing unique class names.

JS-powered theming. Ability to create and switch themes using JS.

CSS-in-JS Cons

Performance Hit. No matter which way you slice it, CSS created through JS cannot be faster than a plain old CSS stylesheet. Work has been done to statically extract the CSS out at build time, projects like CallStack's Linaria, and Facebook's stylex, but the most popular CSS-in-JS libraries, emotion and styled-components do not support this.

Developer ramp-up time. CSS-in-JS is a paradigm shift, and costs time to get a team up to speed on how to use it. Each framework has different APIs as well so knowledge of one is not directly transferable to another, contributing to JS Fatigue.

Lack of discipline. Having the full power of JavaScript can be as much of a detriment as it is a boon. Switching to CSS-in-JS leads developers to throw away years of best practices and methodologies around developing CSS systems. CSS-in-JS has not had the time to bake that CSS has, libraries are still evolving and innovating and systems are still young.

No portability. The JavaScript ecosystem moves fast. We have gone from jQuery to Angular.js to Angular 10, Vue, and React in ten years. But it is still a small part of the web. WordPress powers 37% of the web, and many sites are built with other tech stacks, Python with Django, Ruby on Rails, static-site generators, PHP, and so many more cannot use CSS-in-JS. A company that wants to build a design system across all their web properties and chooses CSS-in-JS locks themselves into that JS framework and that CSS-in-JS library. The marketing site, the app, the help docs site all need to conform. Maybe this isn't an obstacle now, but what happens when the next shift comes along and React, Vue, and Angular are no longer the new hotness? You have a massive pile of technical debt that will keep you from moving to the bleeding edge. Even if your developers wanted to do a new one-off project using that new shiny framework, they can't without rewriting and porting everything.

A Step Back

Of all the downsides of CSS-in-JS, most can be resolved, but portability remains a large issue. CSS is completely portable, it is agnostic to the tech stack you work with. A design system built with CSS and served over a CDN can be imported with any tech stack your company wants to use. We brought CSS in because we brought HTML in and that worked like a charm. One key difference between HTML-in-JS and CSS-in-JS though, is that HTML is not meant to be portable. You do not create a design system around a set of HTML structures. HTML is simply the markup and will be unique to each site you have. CSS though, is universal. Your company has a brand, a feeling they want to evoke, a recognition they want to build with the customer. You want all your sites to have that same look and feel, and letting your CSS be portable is the best way to achieve that.

Is CSS Really That Bad?

Of all the upsides of CSS-in-JS, most are negligible with modern CSS. CSS modules provide scoping to eliminate the cascade. CSS modules allow you to colocate your styles with your component and import them for use in JSX files. CSS modules interop with all the JS build tooling to get fast build times. Build tooling improvements have not been isolated to CSS-in-JS, linters and dead-code elimination exist for regular CSS files too. Libraries like Jed Watson's classnames provide good enough ergonomics to conditionally compose styles. CSS Variables provide the ability to do theming with better performance than CSS-in-JS. We find ourselves in a position where CSS-in-JS feels much more like a step sideways, or a step backwards because it locks us in and we lose portability.

Where We Go From Here

Does this mean we should abandon CSS-in-JS? No, it has a place. Certainly Facebook is making a case for how well it has helped their FB5 relaunch perform. But, that doesn't mean it is the solution for every company, and every team. I implore you to consider the tradeoffs when choosing to go with CSS-in-JS. Lack of portability, need for training, performance impact, lack of discipline, if you value the ergonomics it provides above all else, go ahead. I have loved using CSS-in-JS as a developer, but I also really don't mind modern CSS that much.

Sign up for our newsletter

Get our latest articles and our most exciting updates delivered straight to your inbox.

Get started with Level today.

Don't be left behind, join us on a higher level. Contact us for more information and a demo.