original post @ Linguine Blog
CSS is awesome, and it’s easy to get started with.
But front-end applications have been scaling at a massive, and complex rate that I don’t believe the current CSS architecture is designed for the job.
I still believe that the current CSS architecture has a place in this crazy world for small sites, and even small applications.
I’m going to list a set of problems that I’ve come across with CSS over the 9 years of developing for the web.
And I believe CSS in JS solves these problems.
I will be demonstrating how CSS in JS solves these issues by using 2 libraries Styled Components and React.
CSS problem #1: Global namespace
I created a style sheet that contains CSS code for a container element.
The container style will increase in size if it also contains the class name home.
Now I have created the home page HTML, imported the stylesheet, and have added the class names to the HTML elements.
But wait, I need an about page! Let’s create that now.
I’ve now created the about HTML page, imported the style sheet, and created a new container element.
Great, right?
Not exactly. The style sheet that I imported contains styles from the home page.
And there is nothing to stop me from using class names that was designed for the home page.
Over time this simple site will grow to have thousands of lines of CSS, and HTML code.
And CSS rules that have been defined in the past will be re-used across the site. The problem lies when a engineer attempts to change a class rule.
It has a very high potential of breaking or changing other parts of the site that were not meant to be modified.
CSS in JS allows us to keep styles encapsulated to a React element.
I’ve created 2 components here.
The first component is named, Title.
Title is responsible only for styling., The second component is Greet.
Greet is responsible using the styled component that I created and displaying the greet message to the user.
Title been defined as a local style. No other React component or HTML element will be able to access these styles. Safe!
CSS problem #2: Implicit dependencies
This is called style of writing SASS/CSS is called BEM. Ever heard of it?
Probably not.
BEM is one of many CSS methodologies. And the objective with a CSS methodology is to reduce the lack of built-in scoping mechanism.
OOCSS is a method to separate containers and content with CSS “objects”.
We also have:
- SMACSS
- SUITCSS
- Atomic
Nonetheless, each of these solutions are just a quick patch solution.
CSS problem #3: Dead code elimination
Why download CSS code that isn’t going to be used?
CSS in JS can dynamically clean up CSS code that is not being used.
CSS problem #4: Minification
CSS out of the box doesn’t have a feature to minify code.
For big applications unminified CSS code can get fairly big, especially with crazy amount of white space (indentation) we add to the stylesheet.
To minify CSS code you’ll have to use a third party service online or setup dev task to minify your code.
Which just creates another dependency your CSS.
CSS problem #5: Sharing constants
CSS supports a sharing constants with their built-in function called var().
But it does not support IE. And it barely supports Edge 15.
We can say, “Microsoft stop support of these browsers.”
But according to W3Schools, which they get 50 million visits per month.
They say 4% comes from IE and Edge.
That’s a total of 2 million users using IE and Edge. Not really numbers that we can ignore.
And with a recent project with Verizon Media, the application needed to support IE 9 still.
So var(), goes right out the door. For the moment.
Another con is that CSS variables cannot be accessed on the server side either.
Let’s take the React example above and modify it a bit to see how we can use constants across our application.
I created a new file named constants.js, and inside that file it contains a value for the primary text color, FireBrick.
I than updated the Greet component to use the new constant I created.
First I imported the new constant into the Greet.js file. Then I use a technique called interpolation inside the Title component.
The hard-coded color value was swapped for the constant.
While I’m at it, I’ll create a new component called Button, and it will use the same constant.
The only difference is that primaryTextColor is now being used in 2 css properties for the Button component.
The components will stay consistent now.
CSS in JS benefits
Besides solving those 5 issues above, it comes with some additional benefits.
- Generates minimum CSS requires
- Good runtime performance
- Supports dynamic styling
- Easy to pre-render important CSS
Conclusion
At the end of the day we’re not getting rid of CSS. We’re just adding JavaScript to enhance CSS.
The old CSS architecture is perfectly fine for small sites, and small applications.
But it may not be appropriate choice for medium to big size applications in 2019.
Sure, we can add SASS, methodologies, and even CSS modules into the mix, but again, those are small patches that require strict rules, and tooling.
Those are not solutions for the future.
I would say that CSS in JS is not the ultimate solution, but it’s the best one we have so far.
Let me know your thoughts and comments on Twitter.
Top comments (12)
1. CSS problem #1: Global namespace
CSSModules or BEM, as just a "more safe way to name things" could save the day. But CSSModules would be enough.
Is there anything, that CSS-in-js could improve? No.
2. CSS problem #2: Implicit dependencies
In short - you are wrong. This is not quick patch solutions, and BEM/Atomic approach(even if there is no similarity between then) could be used with "CSS-in-JS". You just don't get the point - they are about "structuring" the rules, not writing/naming them
Is there anything, that CSS-in-js could improve? No. The problem is perpendicular.
3. CSS problem #3: Dead code elimination
How? Probably you might just delete it?
What if you have a one style file per component? - You probably might just delete it. Or not import it if you didn't use component.
Is there anything, that CSS-in-js could improve? No. It's the same.
4. CSS problem #4: Minification
Miniwhatthing? How you think CSS-in-JS "minifies" their code? It does NOT do it. Instead of it you have to download some(a huge amount) of JS to parse, prefix and apply your styles in runtime.
CSS-in-JS usually consumes more space.
Is there anything, that CSS-in-js could improve? No. They even much worse.
5. CSS problem #5: Sharing constants
constants are supported by SASS or LESS. Supported perfectly, and you can build bridges between JS and CSS using webpack loaders.
The problem is with variables, which you might not need.
Is there anything, that CSS-in-js could improve? Yes. The only thing CSS-in-JS can rule.
Total
Zero-runtime
If you like "CSS-in-JS" - use "zero-runtime" CSS-in-JS libraries. They produce CSS, while being "JS" for you
Styled-Components? All the reasons you listed - are falsy. Believe the old pirate.
Those are nice libraries that I've never seen until now. I'll have to do a deep dive on them.
Overall, I don't believe traditional CSS architecture belongs in a 2019 (mid to big size) application.
We're moving towards a componentize architecture and traditional CSS structure doesn't work because of the problems I've mentioned above.
With that said, CSS modules I have heard of and I think it's great but it adds more dependencies to an application and more knowledge about Webpack configuration that an engineer needs to know.
I don't think there is a good enough reason to why need to add all that complexity or even know it.
Writing CSS in a JS file does solve the problems above, and you honestly don't need a library to do so. You can inject it inline.
Now you might say, INLINE CODE IS THE WORST!
It was horrible before because you had to write it manually, but now you can just have a style object and inject into the style attribute. You may also move the style object to it's own file for "separation of concerns".
You're still writing CSS, but just doing it through JavaScript.
Probably the problem is with traditional CSS structure.
It's one line. And even CRA supports it. So - there is no complexity.
The problems are solved by a specialized library, not CSS-in-JS as technology itself
I would say - INLINE CODE IS THE WORST!!! You got me :P
There is one, a single one reason not to use inline css - meta selectors.
Meta selectors give you the ability to:
:hover
,:focused
,:active
states, which you still could emulate with a pure js, but better dont:before
or:after
, which could simplify your html and make code cleaner. It's still possible to just add mode nodes to the markup, and joggling everything with javascript. But there are situations, when you have to use all features listed above simultaneously, like add:after
element for:hover
state on some@media
, and CSS code shall be preferred.And every time, when you are writing MORE CSS code than JS code, and that could be a thing, if you really use all possibilities of CSS - you might prefer CSS-in-CSS, not in JS.
It seems to me - you are underusing CSS features. And, actually, shall not have any issues in this case - CSS problems are problems of a scale.
Agree. CSS module system is the best
import styles from './App.module.scss';
which can be use after as
<div className={styles.App}>
...
</div>
var() is actually very useful when you only have to focus on one browser, in this case Chrome. When will that happen? ElectronJS.
ElectronJS uses chromium so it supports the lastest CSS features as var() and you can actually build apps on it.
That’s true. Most modern browsers support var().
I currently have the misfortune of working on applications that need to support IE 9
The main issue with CSS in JS libs like Styled Component in that it reloads the whole app on every change. While CSS module system works perfect atm for me.
I would never put my css into components so they grow as hell. Why should i do it?
Also zero linting and intelesence. Who invented this and why?
You don't get linting or intellisense in traditional CSS anyways, so... By the way, why not? If it works it works...
Well IntelliJ Idea checks your csss.
whereas
And what about CSP?
Does it inclide nonce?
Or must be unsafe-inline enabled?
This might help
Resource link