Picking the “perfect-for-you” CSS-in-JS solution
At Amazee Labs, we love CSS! With its latest features like grid layout and cool animation effects, what’s not to love?
Your application’s bundling tool, e.g. Webpack or Parcel, will now bundle the CSS with your JS application. But note there is no other integration; you have to ensure that the CSS is optimized and in-sync with your JS during development.
However, from even a little research, it’s apparent that we could have some big wins from integrating our CSS more closely with our JS; think: chocolate AND peanut butter big.
So how do you pick the best CSS-in-JS solution?
I’m aware of at least 68 different CSS-in-JS solutions so, obviously, there are a lot of different opinions about which is best. Many CSS-in-JS projects give a hat tip to the seminal presentation by Christopher “vjeux” Chedeau, “React: CSS in JS”. In it, he outlines 7 specific “problems with CSS at scale” that Facebook was trying to fix or minimize. Many of these are the same problems that my team and I (a non-mega-corporation) have.
Unfortunately, after careful re-reading of the slides, I was shocked to see in the very first slide that Facebook defines “problems of CSS at scale” as being the problems “in a codebase with hundreds of developers […] where most of them are not front-end developers.” [emphasis mine] Say, what?
So not only do we have dozens of projects to choose from, but many CSS-in-JS projects are optimized to solve problems that front-end developers don’t have. At Amazee we have well-rounded teams that include front-end developers; everyone works together to solve problems so we never have backend developers floundering with CSS features.
Picking the correct project means carefully determining what problems we want to fix and figuring out how the API of a CSS-in-JS project solves those problems. In contrast to Facebook’s 7 CSS problems, as a front-end developer who likes CSS, the 6 CSS problems my team needs to solve are:
- Separation of concerns by task (instead of by technology)
- Locally-scoped CSS
- Prevention of unused CSS (dead code elimination)
- Removal of duplicate selectors needed for CSS media queries and pseudo-classes (making code DRY: don’t repeat yourself)
- Fast front-end performance (both JS execution and browser caching)
However, evaluating all 60+ CSS-in-JS projects using our 7 criteria would be a monumental task. Fortunately, we can also group all of these projects into three basic API approaches:
- CSS as an object literal
- CSS as a template literal
- separate CSS file
This categorization will help us quickly figure what works best for us.
APIs using Object literals
style properties on the app’s HTML which meant they didn’t support media queries or CSS pseudo-classes. Oops.
Fortunately, nearly all of these projects have fixed that problem by allowing you to specify locally-scoped class names inside the object literal. Here’s what that looks like:
The above object defines
.warning rulesets. As you can see, the syntax here looks almost identical to vanilla CSS. But with the added bonus of fewer semi-colons and way more quotation marks and commas!
If you like CSS, you will not like this group of CSS-in-JS projects. If you eliminate this group, you’ve just eliminated approximately 61 of the 68 CSS-in-JS projects. whew.
APIs using template literals
The next group of CSS-in-JS projects looks much better to the eyes of CSS lovers. This API uses ES6’s new template literal feature, which is just a fancy way of writing really long strings with backticks. In the example below the
css`` syntax takes the really long string between the backticks and passes it to the
css function. That
Some projects go a step further and provide functions that output your chosen HTML element with the provided CSS. In the example below
styled.div`` is again a function that handles template literals, but it also outputs a
div element with the CSS applied to it.
APIs using separate CSS files
The last “group” is actually one of the oldest solutions and there’s only one project in this group, CSS Modules. I would link to that project, but its website is horrible at explaining what it is. Instead, I’ll show you an example.
The CSS file above is actually processed by PostCSS, the same family of projects that includes the automatic vendor prefix tool, autoprefixer.
In fact, CSS Modules is just a thin layer that applies your PostCSS transformations to your CSS files and then passes that to your bundler tool. If you use webpack’s css-loader or postcss-loader, you’re already using “CSS Modules”.
What kinds of transformations can PostCSS do? For the example CSS file above, I chose the
Simple, right? I just wish the CSS Modules website was clearer.
To be continued…
By categorizing CSS-in-JS project APIs, we were able to eliminate 61 of the 68 projects that only support the object literal syntax. In my next blog post, we will look at projects using the other two API choices, examine each of our 6 CSS problems in detail, and use these criteria to find my team’s perfect CSS-in-JS solution.
Given our wealth of CSS-in-JS choices, there is no one “perfect” solution; there is only what is perfect for you. While you may not agree with our final pick, I hope the process we outline helps you to find the perfect-for-you CSS-in-JS solution.