I understand the struggles and problems this article lists, particularly the "re-use or duplicate" quandary, but then I'm not sure how "CSS in JS" solves all of them. Seems to me like the question becomes, do I re-use this React component, or duplicate it?
I don't really understand conversations about reuse in react, since the one-way data flow model it uses allows almost any functionality to be extracted into a composable single-purpose component. If the view components are kept pure I'm not sure I can think of an instance where code wouldn't be easily reusable except slight variations in the design, which is a problem no matter what framework you use (or none at all).
Edit: whoops, didn't realize you were talking about styling, not functionality.
The core idea isn't strictly to generate CSS from JavaScript per se, but to generate CSS in whatever code is generating your HTML. In React, that's JS, but if you're generating HTML server-side in PHP or Ruby, the argument calls for generating CSS in PHP or Ruby.
vjeux's talk identifies seven problems:
1) global namespace: CSS has a page-global namespace for classes
2) dependency management: if you forget to include CSS, but another module/component on the page includes the CSS you need, your code will seem to work, until they remove their dependency and your code will magically break
3) dead code elimination: you can't know whether a CSS rule can be removed unless/until you can prove that the HTML generator won't generate any HTML that matches its selector, which can be impossible in the general case
4) minification: you can't minify class names without coordinating with the HTML generator
5) sharing constants: "padding: 5px" has to be kept in sync with the HTML generator "buttonPadding = 5"
6) non-deterministic resolution: loading CSS files in a different order results in different rules with the same specificity winning ties
7) isolation: component clients can use CSS to style the internals of an element, making the HTML structure implicitly part of a component's API
vjeux calls for applying generated styles as inline styles with the "style" attribute, primarily because it's straightforward to implement. You may be able to get better performance by generating a <style> tag on the server side, or extracting a CSS file from the HTML generator instead.
Beware that if you're generating your HTML only in client-side JS, that can be bad for performance, and CSS-in-JS is likely to make that worse. At least run your JS on the server side, so you can send HTML + CSS to the client on first load.
(I work on this team at the Guardian but views my own.)
You are definitely right that there are still challenges around how you structure and re-use JSX components.
However, our primary motivation with CSS-in-JS was to achieve decoupling between different parts of the page when it comes to CSS. I.e. if I change this part of page A, will I break other parts of the page? Or even, will I break something on a completely different page? By scoping styles to components, CSS-in-JS helps avoid these kinds of issues. Of course, it introduces its own complexities.
This is really not an academic concern on a large website with daily commits by developers often from different teams and not necessarily experts in CSS. Only last week I had to fix an issue of this kind.
Hmm... Don't take this the wrong way but the point of CSS is that it can be modified by people that are good at, you know, CSS - a class of people that generally does not include your average java / PHP / javascript developer.
I agree entirely with 'scoping styles to components' but css in js is a massive step backwards when this can be accomplished much more simply by maintaining a less / sass / css file in the same folder as the js and importing it.
My two cents, as a contractor who is paid to fix other people's code: there is an aspect to semantic HTML which is the descriptive nature of attribute class names. This is completely destroyed by css-in-js.
In short: I can easily track down the styling (and probably the component) in the code based on an attribute classname. How on earth do I do that when every single class is named some combination of 'R23RG67ED'? I know there are things you can do in Webpack to create some sort of descriptive name ('component_1-wrapper_2-div_3-my_wacky_component_5-GEWRCER anyone?) but a) nobody does this and b) if the only reason we're implementing css-in-js is for issues of scope, surely this is not a step forward?
Hey thanks. I think probably our experiences are just different here. I've found that convention (one css file next to the JS component in this case) is sensible but can break down over time or with larger dev teams. In these cases, I tend to prefer a technical constraint over convention when there is a choice between the two and it's for something important. On tracking down the styling, we haven't found identifying the relevant component where CSS lives difficult in practice but I can see that might not always be the case.
Ha yes definitely. One of our motivations in this work is to be able to identify and serve only the CSS that is needed for the specific page/components being requested.
9 comments
[ 4.3 ms ] story [ 29.3 ms ] threadAm I wrong?
Edit: whoops, didn't realize you were talking about styling, not functionality.
The core idea isn't strictly to generate CSS from JavaScript per se, but to generate CSS in whatever code is generating your HTML. In React, that's JS, but if you're generating HTML server-side in PHP or Ruby, the argument calls for generating CSS in PHP or Ruby.
vjeux's talk identifies seven problems:
1) global namespace: CSS has a page-global namespace for classes
2) dependency management: if you forget to include CSS, but another module/component on the page includes the CSS you need, your code will seem to work, until they remove their dependency and your code will magically break
3) dead code elimination: you can't know whether a CSS rule can be removed unless/until you can prove that the HTML generator won't generate any HTML that matches its selector, which can be impossible in the general case
4) minification: you can't minify class names without coordinating with the HTML generator
5) sharing constants: "padding: 5px" has to be kept in sync with the HTML generator "buttonPadding = 5"
6) non-deterministic resolution: loading CSS files in a different order results in different rules with the same specificity winning ties
7) isolation: component clients can use CSS to style the internals of an element, making the HTML structure implicitly part of a component's API
vjeux calls for applying generated styles as inline styles with the "style" attribute, primarily because it's straightforward to implement. You may be able to get better performance by generating a <style> tag on the server side, or extracting a CSS file from the HTML generator instead.
Beware that if you're generating your HTML only in client-side JS, that can be bad for performance, and CSS-in-JS is likely to make that worse. At least run your JS on the server side, so you can send HTML + CSS to the client on first load.
You are definitely right that there are still challenges around how you structure and re-use JSX components.
However, our primary motivation with CSS-in-JS was to achieve decoupling between different parts of the page when it comes to CSS. I.e. if I change this part of page A, will I break other parts of the page? Or even, will I break something on a completely different page? By scoping styles to components, CSS-in-JS helps avoid these kinds of issues. Of course, it introduces its own complexities.
This is really not an academic concern on a large website with daily commits by developers often from different teams and not necessarily experts in CSS. Only last week I had to fix an issue of this kind.
I agree entirely with 'scoping styles to components' but css in js is a massive step backwards when this can be accomplished much more simply by maintaining a less / sass / css file in the same folder as the js and importing it.
My two cents, as a contractor who is paid to fix other people's code: there is an aspect to semantic HTML which is the descriptive nature of attribute class names. This is completely destroyed by css-in-js.
In short: I can easily track down the styling (and probably the component) in the code based on an attribute classname. How on earth do I do that when every single class is named some combination of 'R23RG67ED'? I know there are things you can do in Webpack to create some sort of descriptive name ('component_1-wrapper_2-div_3-my_wacky_component_5-GEWRCER anyone?) but a) nobody does this and b) if the only reason we're implementing css-in-js is for issues of scope, surely this is not a step forward?
Edit: just to add, the comment in this thread https://news.ycombinator.com/item?id=19608498 does a much better job of explaining all the benefits of CSS-in-JS.