Why or why not choose CSS-in-JS

Local Scoping vs. Readability; Encapsulation vs. Flexibility Advanced Functionality vs. Learning Curve, Minification and others

Image for post
Image for post
Photo by ian dooley on Unsplash

CSS-in-JS has gained increasing popularity recently. Before I tried it, I already heard about all the happy stories and 5-star comments about it. So then I jumped in — it was a pretty fun experience — but I also have to admit that it’s not that glamorous and hassle-free as I thought.

So I just want to post here some highlights and a few concerns that you should think ahead before you shift your project from traditional CSS to CSS-in-JS.

But first, what is CSS-in-JS? Well, the term refers to a pattern where CSS is composed using JavaScript instead of defined in a separate stylesheet.

And how is it become so popular recently? “Recently” is a vague term. To be more specific, it should be “the era when component-based front-end Javascript framework rise to power”. I.e. React, Vue… The component structure breaks down a big application into many smaller units and makes creating reusable components easier and a natural way of doing so.

With this trend, the traditional CSS stylesheet becomes less ideal as it’s difficult to tell the order of each individual stylesheet being load and can lead to style for component A overriding that of component B if naming and specification is not properly managed.

But with CSS-in-JS, it becomes less of an issue (Actually no issue at all!). Since now the CSS style couples with its JS file in one component, making adding and removing a certain component posing no conflict with other styles.

So here are some valuable attributes CSS-in-JS bring to the table, and we are also going to discuss the drawbacks as well.

Traditional CSS is “cascading style sheets”, that means, it is global by default. So as the example above mentioned, you might have some sub stylesheet overrides your other ones and ends up undesired behaviour.

So CSS-in-JS solves this problem completely by either of the 2 solutions:

  • Generating 100% unique selector to the element
  • Creating in-line style to the element on the fly

For example, in the Material-UI I uses, I have a <li/> tag, and the autogenerated classname is:

Unbelievable! This obviously poses a threat to readability and debugging. At least for me, there were situations when I feel trapped in a labyrinth of similar strings debugging using Chrome dev tools.

There are, however, some other libraries generating inline CSS on the fly. While this avoids problems with readability, it inevitably hinders the ability to use some common CSS features e.g. media queries and modifiers. There might be some way to get around it, but then you are adding another layer of complexity to your problem.

On the other hand, you can still avoid the problem with global scoping while use traditional CSS. Modularity solutions through Naming conventions like BEM or Pre-processors and Post-processors like LESS, SASS are all out there.

One point the supporters of CSS-in-JS likes to mention is that the style and functionality becomes one unit, and when the function or even the application needs to be exported, the two are bundled together. This helps to achieve encapsulation through exposing only one API to the outside, and thus makes modifying and changing code less error-prone.

But on the other side, locking your CSS together with your JS makes your application less flexible. Since most CSS-in-JS libraries only fits well with component-based frameworks like React and Angular. (For example Styled-Components only works in React & Preact). Well, all is well when React and its alike are still in mass adoption, but it’s likely that there will be some other new tools coming in the future.

By coupling your CSS with a specific framework, you are losing the flexibility to transit your project into some other framework without massive refactoring on CSS — writing from scratch!

With CSS-in-JS, you can do some crazy thing your styling. Looping, state-based styling, conditional… you name it. This is because your CSS is written in Javascript.

But the seemingly shinning life comes with a cost.

Firstly, there’s a learning curve. For basics, you might just need to know how to insert variables and string interpolation. But for advanced usage, you might need some more grilling — the learning curve is especially steep for new learners who might need to get their head around basics JavaScript or React first. For example, some common usages in Material-UI derives from the concept of using React HOC and Hooks.

Secondly, with advanced functionality comes with more responsibility. You have to be more careful when write code, otherwise you will run into some bugs that you will not encounter previously in CSS.

In contrast, traditional CSS is error-tolerant. If a CSS rule is not supported on some browser, it will be simply ignored.

One thing that CSS-in-JS helps to improve performance is through minification of classnames.

But traditional CSS has its own approach (maybe better).

You are free to inline load the critical path CSS and make the rest of the CSS loading asynchronously.

Also to utilise the full power of CSS-in-JS, it’s recommended to use Server Side Rendering (SSR). But this adds extra requirement to your application which you might not need to think about it without it.

In conclusion, I feel CSS-in-JS can be a good option if you are working on a component-based framework and are not afraid of writing CSS in JavaScript.

On the other side, for people who prefer traditional cascading style sheet, but would like to improve their CSS developer-experience, I believe tools like SASS are enough for you to take your CSS to the next level.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store