An interesting topic when doing Web Development and nowadays not only Web Development is choosing how your Application will be styled. In today's post I will be comparing some of the pros and cons in CSS as well as in CSS in JS.
What is CSS?
Cascading Style Sheets, is a technique to change the look and feel of your Web App, you do it using selectors (what rules you want your styled to be applied to), selectors can be via created HTML tags, ids, CSS classes, etc; once you have your selector you can set different props, as font color, background color, font family, etc.
One of the main advantages of CSS is that you can change the look and feel of many elements at once with a selector.
/* This rule will set the font-size and font-color
as 12 pixels and orange to all the paragraphs in our whole application */
p {
font-size: 12px;
color: orange;
}
Now, what is CSS in JS?
Is nothing more that applying styling to your Components using CSS props via JavaScript, how this is possible? There are many ways, one it's adding inline styles (props) to your component.
// This will render a component (build with React) with the same
// props as we defined in the previous code
const MyComponent = props => (
<p style={{fontSize: '12px', color: 'orange'}}>hello</p>
)
Another way to do it is using a library as EmotionJS that will generate some CSS classes for you and will inject them into your Components.
// This will render a Styled Component with the same props
// as the two previous examples
const MyComponent = props => (
<MyStyledP {...props}>hello</MyStyledP>
)
const MyStyledP = styled.div`
font-size: 12px;
color: orange;
`
One of the main advantages of CSS in JS is that you have only the CSS your component needs, preventing any overrides and making it usable as a standalone piece of code.
CSS
Pros
The standard to change the look and feel in Web Development
In the old days was really hard to keep the same color for different components and was really easy to have a lot of duplicated CSS (when multiple developers were working in the same project). This was because there was no variables to persist non changing values and there was no easy way to reuse rules. Then it became the standard with the war of different browsers as Internet Explorer, Mozilla and then Chrome.
Can use preprocessors
Later preprocessors as LESS and SASS came to make the use of variables and reusing code possible, you could easily nest your inner selectors being wrapped by the main CSS class and also add some variables to it.
Good performance
Since it's and became the standard it's really easy for Web browsers to apply the styles, they have been doing it all the time. Also, the output code applied to the HTML elements is only the needed even tough the CSS code can contain non needed and non used code.
Applying a CSS theme/skin is easy
If you follow a good naming for your selectors and the use of namespacing, will be really easy to come with a different theme and apply it to your Web App.
Cons
Naming is hard, unless you follow BEM or similar
As CSS became the standard, patterns to apply a good CSS styling became popular, one of those is BEM (Blocks, Elements and Modifiers), following this out class name generated will be something like:
/* block--element-modifier */
.button--state-success {
/* here you put your css rules */
}
Easily to commit typos and override props, which leads to use !important in some cases
There's a high possibility that as developers we will have typos in our code, and there's a high possibility that someone will redefine an existing CSS class, and the one at the end will be the winner, unless someone uses !important
which is really nasty.
Dead code risk (dead rules) and hard to maintain
If in the Dev Team there's not strict rule on removing unused code more and more CSS will be created, and depending on the way you use to create more CSS files the harder will be to detect where you need to cut/remove the unused code, this also makes it hard to maintain
Need to worry about compatibility with browser's CSS extensions
If you are managing CSS manually you need to worry about different CSS extensions as: -moz, -webkit, -ms
CSS in JS
Pros
Uses CSS which is the standard
So you don't need to learn anything new to style your components since you've been using CSS all the time.
No need to worry about naming or overriding of props
You don't need to worry about overrides because the CSS used in your component lives in your component only.
Using frameworks as EmotionJS generates browser specific extensions as -webkit, -moz, etc
When using pure CSS you need to worry about the specific browser extensions, however when using this pattern, the library does that for you, generating any of them, this is a relief because you know that as long as the library is supported by the browser, the rules will be available.
Easy to maintain
As the CSS is in the component only it's easy to remove the CSS you no longer need. Also if your component needs some specifics you can modify those specifics depending on the use case passing the variants as props. And the best, if the component is no longer needed you only remove it and that's it. NO SIDE EFFECTS!
Cons
Performance may be affected because of the computation to inject the CSS
Since every component has its own CSS rules the JS bundle can easily grow, and in the other hand the JS needs to be processed by the browser to apply the CSS while in the other hand (using CSS only) the CSS is ready almost at the same time as the HTML components.
Hard to reuse rules
The rules applied to your components are only living in your components, this makes it really hard to reuse the rules you apply to your component to other components. However, if you are using this pattern, doesn't necessarily mean that you cannot use CSS, so mixing both approaches can solve this issue. :checkmark:
Applying some themes, skins may be more complicated but can be generated from a JSON which could be as
Applying themes when using this technique at some point could be harder compared to using CSS only, however if you have a good architecture and a good definition on how you want to use your CSS in JS you can easily spread the props from the parent component to the most inner component. Plus you can use some of the CSS variables advantages. 😉
Is it still CSS? Cascading is lost
IMO the most important paint point is that Cascading is lost and this means you cannot have a CSS in JS that will apply to a nested component, well you can, but you will be violating the principle of this technique which is independence in your components. This loss makes a lot of noise when deciding wether to use or not this technique.
Conclusion
As a personal conclusion I don't think there's a best option, it will depend in your project needs. However, nowadays I'm combining the two approaches making one stronger when the other is weak. I can use CSS variables and apply it to my Components and isolate in the Components what needs to be isolated, just as I would do it using namespacing.
When would you use one or the other?
Thanks for reading!
Top comments (12)
I much prefer Scss stylesheets to css in JS. You get basically everything you could need out of Javascript, but with better reusability and performance. Additionally, it keeps the cascade which is good for learning and can easily be used to your advantage.
I see Tailwind as more of a problem in search of an audience than a solution in search of a problem.
I love styled-components in react!
The problems with non-semantic frameworks are pretty well-documented. Having a set of utility classes like
big 10pxpadding widemargin blacktext otherspecificthing
in your HTML is not better than using inline styles. If your website has - for example - a Christmas takeover where things are restyled to be red and green and festive, you're in for a long, boring job rewriting all your components.In my current use case I'm mixing both approaches, using Cascading for the things that can be cascaded and CSS in JS for the things that are capable for that. Let's see where it will end. I will keep you guys posted. :)
I understand how CSS in JS could be useful when creating an app like a spreadsheet or something - the same way I understand why people like non-semantic "utility" frameworks.
For use in general websites and apps I think it has no real redeeming qualities, because of the cascade. It's not just noise, it's like throwing away the entire point of stylesheets.
I can't think of any time I'd want to take a component and drop it onto another site with a completely different appearance and not want to style it to fit in. With CSS, and with sensible semantics, that's no issue; with CSS-in-JS it's more duplication of effort.
It also reduces your ability to drop the same component into different parts of the site. A component fitting in the header might display differently to one in a sidebar, for instance, and might behave differently when the browser resized or changed orientation or switched fro LTR to RTL reading directions. Managing that in JS is going to be a pain in the butt, but I expect people will come out with some over-engineered solution if they haven't already in order to reinvent the wheel.
I know what you're saying. My distaste for Tailwind, however, isn't an "initial" reaction, and it's not specific to Tailwind. I've been aware of variations on these ideas for years, and think they're a very bad direction for development to go.
I'm drawing the comparison between utility classes in general and the idea of CSS-in-JS, because I think that it's a similar fad, and that - barring some kind of AI revolution - it's going to cause a lot more problems as time goes by.
Maybe a better example would be comparing either to the use of tables for layout. You can see pros and cons for that, too - but people aren't making the case for switching to tables in 2020.
CSS in JS when using CSS syntax, and injection of style tags, as in styled components, is great to take advantage of components hiding implementation details. When using JSX for example, the style becomes part of the JSX declaration!
As a consumer of a stylesheet API you gain tremendously over having to learn a map (class -> node) where, for instance, all the decisions made by the creator matter. Of course one can churn out wrapped components with already assigned class names, but that's just duplication of both CSS and JSX.
Without styled system like Chakra UI or Rebass, I don't really like CSS-in-JS much. I prefer PostCSS with Tailwind.
Didn't know about Rebass. Really cool component libraries! Thanks for sharing!
In my current use case I'm mixing both approaches, using Cascading for the things that can be cascaded and CSS in JS for the things that are capable for that.
I'm fairly sure I'm never going to like Tailwind. When I say it's in search of an audience, I mean it pretty much exists because it was low hanging fruit, a quick way to make something popular. People like it, yes, but people like mayonnaise too, so people can be wrong.
The low performance of CSS in JS is a major issue for big applications, especially for mobile devices. Let's not also forget that today, more of half the internet traffic comes from mobiles devices.