CSS in JS - Traditionalist sentiments put to the test

CSS in JS is very much a 'thing' nowadays when it comes to building applications on the web. I decided to test my 'traditionalist' sentiments with CSS and take on an experiment. I went in with an open mind to truly answer the question... is CSS-in-JS it really better than traditional CSS?

I was pretty convinced I knew what was going to be the outcome. I have always had an eye on CSS in JS however never really got around to fully form an opinion on it. Being a ‘traditionalist’ I am very beholden to CSS standing on its own and Javascript having its own space and styling components wasn’t one of them.

As a bit of background, early on in my career, I was in your classic ‘web agency’ operation. Building websites for businesses. Javascript at that time was effectively JQuery, and anything stylistic with Javascript was a right pain. So, let's just say those years were formative in me taking an anti-stylistic approach to Javascript.

I since moved to the product space building large scale applications with a tonne of logic and scaling complexity and really embedded myself in the 'React' world, but still leant on CSS as a styling mechanism.

In recent events, I was exposed to styled-components on a production product and was intrigued by its function. I saw first hand its potential. The idea of housing stylistic variations of the same component in the same file seemed really nice to me.

This made a lot of sense as it kept everything in a nice package. From my experience in large scale application, things in 'nice packages' and components that 'made sense' is an exciting space to exist. With this, everything I needed to know about the button logically and stylistically was housed in the one file.

My conclusion at this time was “It can work for things like components, but if you were to introduce layout styles like grid, it will become overwhelming. So my position was, “anything structural should be CSS, anything logical can be a styled-component.

To put this to the test, I decided on a rather simple experiment. Compose 3 identical UI’s which each have a toggle navigation menu, a banner image and 3 columns. A fairly ‘boilerplate’ agency layout.


Build one the 'old way' using purely CSS (Sass), One the _'new way'_using purely JS (styled-components) and a 3rd to put my position suggestion “logical components in styled-components, and layout in CSS” to the test.

This entire experiment can be found on GitHub.

Pure CSS Approach:

Code: https://github.com/lindsayjopson/css-vs-js/tree/master/css




The general structure of the folders suggests, in the styles folder house global and shared styles and variables. Things like $black, $white, $base-spacing etc.




If we were to look into the contentBlock component you would see:

The separation of concerns here is pretty clear. The index.js file takes care of the React rendering, and the .scss takes care of the layout. In practice, I have enjoyed this separation. It's the classic “put a classname here, place the CSS for that classname there”.

From an onboarding and understanding perspective on ‘how things fit’ is pretty clean and clear.

Pure JS Approach

Code: https://github.com/lindsayjopson/css-vs-js/tree/master/js


The folder structure is exactly that of above, for this exercise I really wanted to make them as close as possible without letting ‘folder structure’ get in the way of the final thought. For this, I effectively merged the .scss file with the .js file, and replaced the style/*.scss with globalStyles.js and globalVariables.js.



To revisit contentBlock/index.js

To me, this makes total sense, you are combining everything regarding a ContentBlock in one place. Its small, its tidy and its logical. However, ContentBlock aside, lets look into our globalStyles.

For this, we need to understand a couple of concepts.

Global Variables. CSS Only.

I created a _variables.scss file which housed all the Sass variables.

This file is then @imported above other *.scss files which makes $white available across other *.scss files.

JS Only.

We have a globalVariables.js file, which contains the following

These can then be imported into files much like any other variable. import { white, black, baseFontFamily } from "./globalVariables";

Global Styles.
CSS Only.

I created a _base.scss file. This houses all the classic ‘base’ styling for an app.

This is then important in the style.scss file which automatically makes those set.

JS Only.

styled-components exposes a createGlobalStyle function which you pass in the same content as above without the Sass Variables`.

Added complexity.

So the stuff we have been playing with up until now have been rather simplistic, not a log of ’style’ is involved and mainly sitting around layout function. For this exact reason, I added a toggle-able navigation. As far as ’style’ goes I would say this is still on the ‘basic’ style, but it was a good indicator of adding complexity to the system.

CSS Only:

The functionality to note above is as follows. When nav_toggle is clicked, the isHidden state is switched to true or null. By doing this, an additional className will be toggled on the nav_wrap of hidden or visible. In CSS we have the following to support this stylistic change.

While I have removed some of the general styling of this component from the above example, I would like to draw attention to the complexity added to the CSS for this interaction.

There are hover effect which impacts nested elements .hamburger .line, we have left: -360px interactions when the navigation is set to .hidden or .visible. We have :hover states of the individual .nav-item. While in the CSS only version, this doesn’t feel too far outside the norm. Whereas if we are to then bring this into JS Only we are faced with the following.

JS Only