Why Would You Even Want to Put CSS in JS?
So, is putting CSS in your JavaScript code really even worth it? Definitely — as long as you are choosing your tools wisely.
Web developers across the world, across libraries, and across technologies agree that the way to develop maintainable user interfaces is to split concerns into self-sufficient components. The idea is mature and widely known — for example, by mobile and web developers who have used the web components approach before. Yet, its popularity on the web has increased during the last few years. Thus, a number of new ideas on handling all the satellite conerns, like styling or state management, have been presented or adjusted. Today, I'd like to focus on the first one: styling.
I used to favor an approach in which one component has a corresponding SCSS file describing its styles. The SCSS file is then imported into a JS file and then adequately managed by Webpack. This solution has enormous power, mostly due to the superpower of SASS itself. The only thing you really should take care of is that the styles you're defining for the component don't override other components' styles.
And that's where the BEM (Block Element Modifier) comes in. If you're encapsulating your styles in blocks and naming them after your component, it's rather unlikely you'll break the component styles of others. Of course, I'm assuming the component name is unique across the system.
CSS Architecture and Methodologies to Deal With Globality
BEM brought many new things into the world of maintainable styles, and widely popularized its naming convention. Thanks to that, if a developer has already had anything to do with BEM, it's reasonably easy to introduce them to a project where this methodology is used. This hasn't always been the case in the past, when custom frameworks, a number of not-fully-developed methodologies, and project-specific naming conventions were quite popular. Also, thanks to the direct binding between JS and CSS files, it's reasonably easy to eliminate dead code. Along with deleting the JS file (or splitting it into smaller parts), we delete or split the SCSS file.
I've made an assumption on component name uniqueness. Now, this might be quite easy to achieve if you're working with a small team and a relatively uncomplicated (or simply young) project. The problem with CSS globality is that it might become a bit annoying if you're intending to place your code in someone else's codebase. For instance, as some plugin on a third-party platform, a new feature added to an existing system. Actually, this is the case even if you simply use third-party libraries for common components, in which BEM methodology might also have been used.
Going Further
Despite all that, I felt like BEM and one SCSS file per component worked fine for me, and the issues addressed above were quite distant. However, I was still curious if I could go a bit further with maintainability and developer experience. I was more than happy to explore the opportunities of CSS modules, CSS in JS, and the idea of inline styles in general.
About a year ago, I got hugely inspired by CSS modules co-author Mark Dalgleish. He lit a lightbulb in my head with this powerful talk at Reactive Conf 2015.
He, as Christopher Chadeau had before, provoked a number of great minds to rethink the way of handling styles encapsulation. Thanks to their work, we've got plenty of new CSS in JS tools and CSS-ish approaches to modules — and not just those based on naming conventions. A number of opinions on how, when, and where specific flavors of styling are worth using spread across Medium, Twitter, Smashing Magazine, blogs, conferences, and local meetups.
Inline Styles and CSS Modules
Initially, I was a bit skeptical about things that might not necessarily be applicable to inline styles. I have to admit that I didn't spend too much time on research when I looked at the topic a year ago. I've jumped back into the topic quite recently. Back in 2015, I briefly went through a number of articles to check if it would work for my future projects. At that time, even though the open source community was doing a great job of developing those ideas to the state of fully functional libraries and tools, I was still more into using SCSS and BEM.
The problems I was mostly worried about were mentioned and addressed by Mark Dalgleish (see the CSS modules talk above). He proposed locally scoped CSS modules as an alternative to the hacks and inconveniences that CSS in JS libraries has been struggling with. With plain-but-scoped CSS, you didn't really have to worry how to apply pseudo-classes, animations, compatibility fallbacks, or media queries. Additionally, you got the modularity idea from inline styles for free.
Also, it made the composability of styles tidier than in inline styles. It gets even more powerful with Post CSS and its enormous base of plugins. And that's just the top of the iceberg. Check out David Wells' talk to get fully sold on the idea.
Something in the Middle
While CSS modules seemed to be a great step forward in terms of maintainability, reliability, and other -ities, I was still very keen to dive deeper. And so I came across some amazing code. An idea I've stepped into was presented by Mikey Murphy in his article. Fascinating stuff. I strongly recommend it. He hasn't only shown how to get the most out of using CSS in JS. He's also presented a powerful architectural idea and great tools I wasn't aware of. Once again, I suggest you go through the article and get the best of ITCSS architecture (Harry Roberts) and the technological stack presented by Mikey.
The concept of getting solid CSS fundamentals for the top of the pyramid and using all the JavaScript tools and goodies all the way down sounded like a plan. All those goodies living there in the JS universe might be considered as an evolution to preprocessors. You can do whatever you want using unified syntax and the power of all the JS tools. And the whole diversity of NPM is available to help you with styling — not to mention explicit bindings (strict imports) helping to eliminate dead code and keeping your code maintainable, and in some cases, actually deletable.
Also, Aphrodite looks like an excellent balance between CSS and JS worlds. You're getting the animations, media queries, fonts, pseudo-classes, nice composition, and possibility to handle fallbacks. At the same time, you're still able to get all the benefits of JS's programmability. There are plenty of similar solutions. You can take a look at Michele Bertoli's repository and pick the one that suits you best.
Strong Opinions, Weak Opinions
Some of these tools will certainly become widely known and some of their concepts will dominate over others'. However, you're still the one responsible for choosing the right tool for the right job. The diversity and modularity in today's front end are constantly broadening our horizons. It's giving us new tools and concepts every day. Yet, it's still important to have solid fundamentals. Respect what we already have! Sarah Drasner raised some concerns (and made a bunch of valid points) during her chat with Kent Dodds. She pointed out we're still missing some tools like style guides generated on the flight. Also, sometimes we might actually spend more time writing higher abstractions over our CSS in JS, while at the end it still has to be interpreted in the browser as a regular CSS with all its advantages and disadvantages.
So, is it worth it? Definitely — as long as you're choosing your tools wisely. A lot depends on what kind of problem you actually have to solve. I think there are many projects where it's okay to start small without tooling around the styling too much. And obviously, there are many projects on a scale I can't even think of. All these tools and ideas are great and worth spreading. I encourage you to find the tools that suit your needs. Experimenting with them will not only allow you to do your job better and ship your projects with satisfaction — it'll also let you grow as a mindful developer.