Phil Zona Dot Net

Why I changed my mind about CSS-in-JS

The first time I wrote CSS-in-JS, I was following along with a tutorial on the GatsbyJS website. There were a handful of different libraries to choose from - Glamorous, Emotion, and I think a couple others - and I hated them all. This was before the rise of Styled Components, but I would have hated that too.

CSS-in-JS felt really, really awkward to write, but more importantly, what ever happened to separation of concerns? I did the real life SMH face as I read about how "convenient" it was to keep all your component information in one place. I know better than these fools, I thought smugly as I closed the tutorial, not realizing that less than a year later Gatsby would be the hottest JavaScript static site generator (maybe the hottest ever) and CSS-in-JS would be a prereq for nearly every frontend tutorial on the internet.

Now I know better. But how was I so wrong, and what made me come around? Spoiler alert: this post contains absolutely zero hot takes.

Separation of concerns

For some context, I've worked with many people who cling strongly to certain ideas about the technologies they use. This is pretty common in tech and my experience with these types of people isn't unique. But it rubbed off on me more than I thought.

Separation of concerns isn't as clear cut as it used to be. I'm not going to say it's dead because it's not, but the way we think about it has evolved in ways that are only easy to see in retrospect. A few years ago, mixing JS with CSS (or HTML - see JSX) would have gotten you laughed out of any forum on which you were foolish enough to suggest it. The three cores of web development - HTML, CSS, and JavaScript - are separated for a reason. You manage the information, content and structure with HTML. You manage the styles with CSS. You manage the logic with JavaScript. On the seventh day, the lord said "let there be separation of concerns" and thus it was so.

Not anymore though, at least not in the same way. And it's not because we don't separate our concerns.

Front ends have changed a lot, obviously, and so has the way we think about them. The old way was useful when templating languages were still considered cutting edge - you would still think about your page structure in terms of those three cores. Now we think about UI in terms of its components.

So what's more useful? Building a button, creating a new file to describe its styles, and creating a new file to add event listeners (after it loads, of course)? Or defining everything about that button in a single file so that you know what you get when you import it?

Nothing is !important

We all hate throwing the !important rule into a block of CSS, only to have it come back to bite us later on. Methodologies like BEM have mitigated the need for this, but ensuring specificity comes with its own cost - your HTML document looks ugly as hell.

And I say this as someone who used BEM for nearly every web project I've done. People try to justify the weirdness of the class naming, and it really is effective when you do it right, but there's no way around the clunkiness it adds to your markup. Not to mention the weird specificity issues you might run into that require a change of class names.

CSS-in-JS solves this problem in a much more elegant way. Most libraries (actually all the ones I know) scope your styles locally. Want to create a button within a certain div? You can just use the button selector without adding a single class.

Modularity is important to writing good code, but not for its own sake. The tradeoff here is basically none, however. Front end libraries like React and Vue are already forcing us to think in terms of components - see above - so CSS-in-JS is actually more congruent with the development process than a SASS directory and an extra step in your build. It's not better just because it's easier - but in this case it happens to be both of those.

But it's WEIRD

Yeah it is. CSS-in-JS is really awkward to get used to - both conceptually and syntactically. Or is it?

Check out the following snippet, a hypothetical red button you might create using Styled Components:

const RedButton = styled.button`
    background-color: red;
    border: none;
    color: white;
`;

I don't think that's hard to read. It might not make sense at first, but it's actually just a tagged template literal that returns a styled React component. If it makes your head hurt less, you can even make this into its own file and export it rather than defining it within another component file - the result is the same.

Requisite caveat section

There's nothing wrong with keeping separate HTML, CSS, and JS files. In fact, if you're learning web development, you should learn it that way first. If you're building a super simple project, you should do it that way. If you're not using a library like React, the old way is fine.

But if you're already thinking about components, why wouldn't you simplify the way you write them?

Obviously I'm not talking about a magic bullet that will make every web app you write look great, but I've come around on CSS-in-JS. I wasn't the first person to have my problems with it, and I'm probably one of the last people to realize how cool it is, but this is one thing I'm happy to have been wrong about. When it's used incorrectly, it can be weird, illogical, and foreign. But when it's used correctly, it can make your frontend much easier to build, maintain, and change. And this is a good thing because good frontend code is hard enough already.