During server-side rendering CSS-in-JS returns a <style> tag with all the CSS inlined.
If you do not server-side render, it does not matter whether you put your CSS into JavaScript or not—your JavaScript app is not going to render anything anyway.
I know this will be unpopular, but after a certain point, noscript users just get a bad experience and that can't be helped. If a developer wants to provide a rich experience, then there will always be certain platform requirements. Without them, you will have a lacklustre experience. It's like saying "I want to have all the whizzy functionality of your app, but I want to access it using a standard, run of the mill, mud-laden potato" - it's just not going to be possible.
I know how the sausage is made, so I know that making a full web app work without JS isn't at reach for most teams/products.
By knowing how the sausage is made, I'm also aware that the line marking the aforementioned certain point is often drawn too early, at informational (i.e. document) stuff where HTML and CSS are fully capable on their own.
You underestimate developers; they can make it work without JS if they have to. But why should we constrain ourselves?! I mean, there is nothing wrong with JS when used properly.
In fact, JS is extremely useful in the browser. It adds to the richness and interactivity of webpages. We must collectively appreciate this, and stop denying this! Even HN is a better experience with JS.
Some sites do give JS a bad name, and poorly used JS is something I hate too, but JS as a concept is something that I wholeheartedly support. Thankfully, the web is mostly opt-in - if you don't like the way a site employs technology, just don't visit it. Simple.
noscript users certainly signed up for a subpar internet experience, but its not just them that should be thought about.
Slow internet connections are a reason to think about the experience when loading JS is slow and/or failed. It's not just 'poor people' who have slow internet - 'rich people' on inflight wifi or on the internet on the train can result in things not loading.
I think this is a big issue with such JavaScript and load heavy web-sites & apps. They forget that they have users without 1GB connections and who can't afford, weather financially or location based, the download the 500MBs of data required to load their web-site. That and hiding CSS inside of JS feels like a sneaky tactic to keep people from editing it? Or does it actually create the CSS on the fly? I wasn't quite sure after reading the article.
There isn't much that can make an in-flight connection seem quick, but we've tried with our PWA (https://usebx.com/app) and to a certain extent, succeeded.
Ok, we do assume that you have visited our webpage at least once in an area of strong signal, however, once you've done that, all the JS is cached and all we transmit back and forth are lightweight, gzipped json payloads, often less than a kilobyte.
I use my own PWA regularly, and found it actually quite usable in-flight.
NoScript users are almost always economically irrelevant to the business posting the page. They tend to be extra aggressive blockers of ads (and therefore ad revenue) and are sufficiently far from the center of the bell curve technologically that they are both a tiny minority and their product needs and wants tend to be edge cases that are not economically efficient for the business to pursue. I get why NoScript users want to run NoScript, but it's the most powerful signal a web visitor can provide a business to say "focus your resources on the needs of others ahead of mine."
React apps have to be deliberately engineered to work without JS at all, via server rendering. Assuming that's done though, the CSS in JS can just be server rendered too.
It's rather easy too if you're using a (great) library like styled components - this functionality is built in and just works with a couple of extra lines of code.
The deeper question here is will the app work at all without JS. That's quite hard to achieve (every client side interaction must have a server rendered equivalent accessible via a url or url params, essentially) but the CSS part is easy.
The only reason I know of to bother supporting NoScript users is so that when you announce your site on Hacker News you don't have to read that one angry privacy guy talking about how bloated your site is because it requires 200 KB of JS.
It doesn't really matter how the JS components are styled if NoScript users aren't loading JS, though I assume you know that and are just trying to make a point that sites shouldn't be using JavaScript.
- Were there moments when you cried back SASS or vanilla CSS?
- In your react example, I see you created <Title> as styled.h1, but that's an awkward way of bootstrapping a component. Even if I used SC, I would still put the style information outside my component code in the same directory. At this point I don't see the benefit over doing something like:
The big win for me is if you're making an SPA, all the knowledge of the app state is already stored in JS (redux, or local state, or handed down as props if using React). So instead of toggling styles on a class, you just hand the state to the styled component, since it's just a function that returns css.
Toggling styles is a good question. I have sometimes multiple classes that have to work together. For example to open a panel, I use some translate/transform, different positioning. How do you compose different styles for a single component?
How do you deal with mobile, where sometimes I have to override dozens of declarations with media queries?
- No! I have not missed class name collisions and specificity wars at all, and I have enjoyed being able to dynamically adapt my styling as necessary.
- This ties into a broader point of having "style components" like <Grid /> and <Row />, which is a very nice way of working in React. styled-components (the library) simply takes that pattern and enforces it across your application. See style-components.com for links to some more resources about this pattern!
Can you say how this affects the classes and ids you add? I'm guessing you use classes and IDs a lot less because you don't need things to match the css against?
Honestly, I think the CSS-in-JS approach is not for me and we haven't used it except for times where there was no other way to do something.
Instead we have used CSS Modules (https://github.com/css-modules/css-modules), first by including it manually in webpack, now it's already built into create-react-app so I just have to install node-sass and call my Sass files ComponentName.module.scss and I can use them the same way in my .tsx/.jsx files that you use CSS-in-JS. IMO that's a lot less messy and makes your jsx files smaller and better to read. Also it's easier to write Sass and have the pros of that language on top.
Did you consider this approach at all and what did you not like about it?
While different from Styled Components, many people still consider CSS Modules to be squarely in the realm of CSS-in-JS. It literally generates a JavaScript module that you must import into another JavaScript module in order to actually use the CSS classes you write, after all.
Having some experience with CSS Modules myself, I thought they were interesting and definitely an improvement, but still left a lot to be desired.
For example: needing to use a helper like `classnames` to join/toggle many dynamic classes together was very ugly and cumbersome. There is also no way to "directly" tie variable state/props to CSS rules – you're still required to use this indirection where a state/prop relies on there being a predefined class/modifier in the CSS file.
With solutions closer to the "fully JS" end of the spectrum like Styled Components, there are no extra "modifier" CSS selectors to come up with to handle the above situation.
Your reasons sound similar to those given for standardizing on in-line styles as much as possible. Both methods are ways to subvert or work around the cascade. I would like to hear from you why you think the cascade works the way it does, and what aspects should be preserved so as to not 'throw the baby out with the bathwater' while adopting these new methods. Thank you!
Honestly, it sounds like you now have a write-only site, as you will have a hell of a time 5 years down the road when the CI changes.
Personally, I find the Vue.js concept much nicer, but even given that, I define my styling in LESS (SASS...) to benefit from inheritance/mixins on the level of styling. Semantic approaches like BEM or Bulma make a lot more sense to me.
It seems to me React has made a feature out of a flaw, much like the intermingling of code and HTML back in the days with ASP/JSP/PHP.
Yup, that's what you can have with precompiled templates. Riot.js introduced the same concept of scoped css years ago, I wish it was more popular. On the other hand it goes against the "it's just javascript" concept of React.
Hm, I don't share your opinion on this matter, to be honest. You can easily avoid this in both Angular (which does it out of the box) and React by including CSS Modules (https://github.com/css-modules/css-modules) which, if you use create-react-app to build your projects, is a 5 minute change to your architecture. So there really is no reason to write that down as a con for React.
You're right, but community support around a certain pattern often makes it the de-facto practice, so defaults matter even for a non-opinionated library (where "defaults" are essentially what tutorials and thought leaders point to)
I have so many small components that I would loathe to have a separate stylesheet. Yes, it's a small thing to just switch tabs, but this is a small problem. And these small problems add up and can be a huge pain. I really really like the SFCs in vue and compare it to a bit of butter on toast. It might be a small thing, but it seems like it makes a big difference.
You can avoid many things by forcing yourself to use this and this practice. In my experience not all developers out there know what is "good" and what is "bad" practice and there are certainly many React developers out there who never heard about CSS modules. Let's say better it's not a flaw in React but a trap which can cause huge maintenance headache in my opinion.
What you linked is "CSS-in-JS" (in the sense that the library/framework you use transforms the output for you, for convenience, i.e., you're not writing BEM or whatever - same as in the original article). Vue scopes the styles by adding a data attribute.
> and has a very wierd concept of how objects work in JS.
What is so weird about it? I personally find Vue vastly more approachable than React is, especially once you have to start writing all the plumbing to get all the libraries you need to go along with it to write a real world app.
> ] It's a templating system with its own rules and mini-DSLs that ends up being compiled into JS.
Vue has the option to use Webpack to compile html compliant templates to JS functions just like JSX (which BTW is not JavaScript and not HTML compliant and is also a separate concept that needs to be learned as well.)
CSS is just another add-on through Webpack when using Single File Components. Nothing really ground breaking here except for the fact that it creates a nice separation of concerns. This is especially true on teams with junior devs or designers. Or with a team that works on a site with mixed MPA and SPA features.
I've read this before. Vue is a framework. It also has a templating system that is not JavaScript, it's valid HTML with attributes that tell Vue how to bind to it. It's really not that difficult.
> Vue's templates are not HTML-compliant. They are just that: templates. That get compiled to JS anyway.
Sorry, but you're wrong here. They are valid HTML.
"Vue.js uses an HTML-based template syntax that allows you to declaratively bind the rendered DOM to the underlying Vue instance’s data. All Vue.js templates are valid HTML that can be parsed by spec-compliant browsers and HTML parsers."
IMHO only the simplest of components featuring JSX that don't read like a spaghetti PHP coding nightmare to me. For the small number of times you actually need the full power of JavaScript you could also use JSX in Vue with a render function if necessary. I personally prefer to keep my templates and logic separate when possible.
> It's not a webpack add-on. It's a part of Vue's templating engine that is essentially CSS-in-JS, they just give you a template to work in.
No, it's not part of the template engine, it's part of vue-loader which is used by Webpack to create single file components.
> it's valid HTML with attributes that tell Vue how to bind to it. It's really not that difficult.
You mean it has at least three JS-like DSLs (which are not JS, and have different rules depending on which context they are in). In addition it has a very weird binding system which I described at length in the linked comment.
Yup. "Not that difficult".
Meanwhile JSX is a single consistent DSL that directly maps to function calls:
<Tag prop=(string or valid Javascript expression)>
other tags, strings, or valid Javascript expressions
</Tag>
That's it. Even "html-like" attributes that people seem to not like... are exactly what HTML attributes are in actual Javascript DOM APIs [1] [2]
> Look, it's exactly what React without JSX is [3]. Only in React you don't need to invent a custom scripting language and binding rules.
JSX is a custom extension to JavaScript. It's not part of JavaScript or intended to be part of the spec or implemented in browsers. In fact, you have to use some sort of transpiler in order to use it. So, it's not just JavaScript.
There's really nothing that complicated in here, if you're familiar with Vue. In fact, it's really easy for me to see what's going on at a glance in one place, which is my personal preference. From my own experience, that's rarely the case when working with React the way JSX tends to get broken up because it doesn't have something as simple as a standard if conditional statement within JSX itself.
I've never claimed you do not need to learn anything when working with Vue templates, you need to understand how the system works, but it took me all of a few hours to understand. The features and benefits that I prefer over React/JSX make that worth it to me.
- or JS-array-like magic binding that gets resolved to a string:
v-bind:class="[activeClass, errorClass]"
- or a magic array with objects that gets resolved to a string:
v-bind:class="[{ active: isActive }, errorClass]"
- or a separate DSL for v-for:
v-for="(item, index) in items"
- or a separate DSL for v-for where you can bind entities from the DSL (which looks exactly like the magic binding to data from the component, what happens when they clash?):
v-for="(item, index) in items" :key="items.id"
- or JS expressions that may be function references that may be things that look like function calls but actually aren't:
> Yes. However, one thing you fail to see is that it directly compiles to function calls.
I understand how JSX works, stop patronizing me. The only thing I fail at is seeing how any of your examples are complicated or have magic so deep that you need to continue to burn Vue at the stake for. In fact, I find your Vue template examples completely intuitive and easy understand with minimal time invested in learning how Vue templates work. It's my preference to spend a little bit of effort up front learning how Vue templates work in order to have clearer separation between business logic and templates.
> It's not a webpack add-on. It's a part of Vue's templating engine that is essentially CSS-in-JS, they just give you a template to work in.
It's regular CSS in the templates and regular CSS in the frontend. There's no JS involved anywhere, unless you count the tooling, but we already use JS tools for CSS processing (PostCSS).
Scoped CSS is an old HTML5 feature that was dropped in favor of style encapsulation using Shadow DOM/Web Components.
I thought one of the beauty of vue template is 'It is not complete set of JavaScript logics, only subset that just able to support proper html structure.'.
It means you can't abuse JavaScript everywhere, creating totally unreadable render function, nest array mapping in Ternary operator and reduce it to what the hell no one can read and destroy all the readabilities.
For me, for you, for everyone, if you using that syntax, then it is simply readable just like html.
Less powerful, but the management definitly worth more.
> I thought one of the beauty of vue template is 'It is not complete set of JavaScript logics, only subset that just able to support proper html structure.'.
The problem with all templating systems is that they start with "we need to limit the amount of logic". But all templating systems find out that this is extremely limiting. So they grow. And grow. And grow. And grow.
You need simple conditional logic. So you end up with v-if and v-else. Then you have to add v-if-else.
You need loops. So you end up with a custom DSL for v-for. And then you expand it to also work on objects. And you need to bind to object produced inside the for loop. And...
And you need to handle events. But events are anything but simple. You need to prevent them, you need to stop or start propagation, you need access to their properties. So you end up with v-on:click.stop.prevent. And function calls. And magic variables in the form of $event.
Worse still, all your existing knowledge about how to apply these concepts in JS is void. Template has taken over.
So in the end you end up with a system that is not really HTML, not really JS, but a weird combination of the two. And the amount of concepts is not exactly more readable than plain React that just uses JS everywhere.
Considering the differences lean towards the DOM interface names for given attributes and properties, I wouldn't exactly call it NOT JS.
It's actually an XML abstraction that closely resembles HTML + JS-DOM, and is then converted into function calls and arguments.
It's also about as close to E4X as an abstraction that I've seen and something I wish was cross browser over a decade ago when it was first introduced by Mozilla and Adobe, but that's a long side-track. In the end, it's very effective and works well imho. Yes there are some more complexity points in some places, but I don't think anything else does it better. Vue imho is comparible, but I don't like it as much and I feel that Angular is far worse in practice.
To me this seems really implicit and magical and strange.
Where is template getting assigned to the code inside the script tag?
Does OtherComponent somehow mysteriously map to other-component? How does one pass arguments to it? Is a .vue file actually HTML or is it parsed somehow to be HTML?
The thing I like about React is the explicitness of it. This is a source code file that exports component X. Component X uses style Y as defined above because it's explicitly passed in as a prop, etc etc.
While Styled Components, Styled JSX or Linaria (which doesn't require a JS runtime for production) are nice solutions, the fact that I can no longer use the colour picker and other tools to live edit CSS from the styles pane in the Elements tab in Chrome Dev Tools, sometimes makes me want to go back to plain CSS to get this functionality back.
Am I misinterpreting something? In my app that uses CSS-in-JS, if I go to the "Elements" tab of my browser developer tools and select an element, I have the option to inspect, add, remove and change styles — including using the color picker and bézier curve editor — and have it reflected live on the page.
When my styled-components app is in prod, the styles are non-editable. When developing, I can use Chrome Dev Tools. On prod, I have to copy paste. Maybe I'm doing something wrong?
I believe this is a result of it using the "CSSOM" browser APIs for speed in production. Unfortunately, browsers apparently haven't figured out how to make such styles editable yet.
It's definitely a limitation of certain CSS-in-JS implementations, but unfortunately one that inherently comes from "using the platform."
CSS in JS is one place where Vue has a substantially better experience. Being able to toss scoped-css, written as normal in a css block is what I call nailing the developer experience. It is all the best parts of css in js with none of the downsides.
I understand your preference for frameworks, but I actually appreciate that it's not out of the box.
I'd rather have libraries focus on one thing and do it well - the Unix philosophy. This lets me compose the appropriate libraries for the problem at hand.
dev tools works fine with both react and Vue if you set it up well, meaning to extract css to a file instead of throw it inline. Most setups extract to a file
The idea with CSS-in-JS is that you don't use selectors. Since you are constructing DOM nodes individually, you don't need to select them. Styled components can accept props, which lets you style dynamically (e.g., using an array index to replace `:nth-child`).
You can define a "theme" object, which you can inject into your styles (with an expression inside the template literal). Other libraries support variables more directly.
What's the problem, you just use them. If you need to reference component itself you can use & selector, works exactly like sass or less. If you want to reference another styled component you import it and ${Component} will reference autogenerated class. Also nobody stops you from writing nested css rules. You can also write cool media query helpers like this https://www.styled-components.com/docs/advanced#media-templa...
I understand the "pit of success" idea, particularly when it comes to more junior devs. But I don't necessarily agree that you need stringent processes to get most of the gains you cite from using something like SCSS or even regular CSS these days. It's really easier than ever.
1- append only? No, each module/feature/widget gets its own CSS file, imported to the main app CSS file. Delete the widget? Delete the file.
2- Specificity issues? Never use IDs, stop using tag names and simple classes and adopt a simple naming structure (doesn't have to be BEM, it could literally be ".widgetName-header")
Since I adopted those 2, I've almost never had dead CSS from deleting features or collisions in my CSS. I do still have a small base set of styles that are shared but it's small enough to be easily manageable.
3- dynamic properties? CSS variables. Not an option? Child classes that apply the dynamic styles serve most use cases. Truly dynamic styles are rare, in my experience.
I'm still keeping an open mind about the possibilities, but my strong opinion (weakly held) is that I still don't see CSS-in-JS as more of a bandaid for people that like CSS and (for many, not all) those that don't have an in-depth understanding of it.
This rarely happens. I would argue that creating an automated system to enforce "rules" should be favored over forcing every developer to know the rules and abides by them.
It is much easier to understand the relationship between css and js when the css is just a js variable.
Having built many large applications using the CSS file method, css modules, each widget gets its own file, co-locating css files with the js, I much prefer using `styled-components`. It provides a ton of flexibility, it opens doors for dynamic css by leveraging js (the hacks I've seen, had to write to get css dynamic is astounding), and I don't have to look very far to see how it's being used because the CSS is literally attached to the component I'm using. All I do in VSCode is cmd+click and bam, I can see the CSS for this component. There's no need for naming convention, there's no worry about global css variables getting into your styles, and there's no digging around looking for css that might be influencing your component. The best part for me is: when I delete the component, the CSS is gone as well. There's no thought put into scouring the FS to find lingering CSS that used to be used.
I love `styled-components` and most of the designers I work with also enjoy it.
It's hard to know when you can delete a rule. Are you positive that all the rules in your component's CSS file only affect that component? Then great, delete the whole file.
What about the individual rules within that file? How do you know whether your app is still rendering any components with the `fancy` modifier anymore? Keep in mind any JS on the page could be be dynamically toggling the `fancy` class, including in very rare circumstances, including from dynamic data that might bring the string "fancy" with it so that you can't just grep your codebase for it. Is it safe to delete the `fancy` rule?
Another problem is that even BEM admits that sometimes nested selectors are necessary. It's right there in the BEM FAQ: "While in general BEM recommends avoiding nested selectors, in this case they are reasonable."
Sometimes you need your button to look a certain way when it's inside a nav menu item.
So what's the solution? Either a nested selector (targeting both the nav item and the button) or a new modifier on your button, like `is-in-nav-item`.
Eventually your app changes and you're not rendering any buttons in nav items anymore. Maybe nav items don't even exist anymore and you at least remembered to delete those. Are you also going to remember all the places in your code you need to track down to delete these obsolete nested selectors/modifiers? Or is there just going to be dead code now?
What if the selector is slightly more general, and you're not sure if it's targeting other things as well? Are you confident that you won't break anything else? CSS selectors are effectively global. Anything could be secretly relying on the styles that a selector applies.
That is the problem. Not deleting a file. Your individual component CSS files are now the "append-only" stylesheets, not necessarily the whole combined stylesheet.
This is where something like CSS Modules comes into its own. You can have (nearly) absolute confidence that what's in the CSS file colocated with the component is only used by that component. Sure, there are escape hatches like `:global(...)`, but those should be considered a code smell.
The beauty of CSS modules over a convention-based approach like BEM is that you end up with cleaner, simpler CSS files -- with selectors like `.Widget .search.error` rather than `.Widget__search--error`. The downside is that there's a compilation step, but chances are that you already have _some_ sort of compilation going on -- even if just to bundle things up.
The way to handle "special" cases for buttons -- like when they appear in certain contexts -- is to allow the calling code to add a class to the button; a class which comes from the caller's own CSS module. Alternatively, use CSS variables:
> 2- Specificity issues? Never use IDs, stop using tag names and simple classes and adopt a simple naming structure
I have one exception to that in my own work, which is to only ever use IDs for styles that affect the layout of a block/component on a specific page. This makes sense since parts of a page layout are usually very specific and not that dynamic(in which case class names might be more appropriate). At the same time, component-level styles should never make assumptions about how they are positioned on a given page.
Let's say that we have a page `/blog/:entry_id`, and this page has a right-hand column to list related blog entries. This component would have an id `#blog-entry__entries-list`, which would control how the related-entries list appears on the blog-entry page(in this case, putting it in a column on the right), and a `.entries-list` class that controls the global appearance of the component.
This way, the entries-list can be used in different contexts without having weirdness caused by a margin working fine on one page but having to be negated on another page where the margin doesn't work. Try to add styles, but do as minimal overriding as possible.
In combination with BEM, primarily for the benefit of all selectors having the same specificity, I've found this separation of concerns between IDs and class names to be very powerful and simple to understand, especially since it doesn't require more verbosity.
Another part of my styling workflow is Sass mixins.
Let's say that we want the entries-list component to appear more compact on another page. Perhaps it appears somewhere on the site index, and takes up a little more room than we'd like.
Since component styles can't assume anything about their environment, and since layout styles(i.e. our ID selectors) can't know about the inner workings of their components, there needs to be a way for layouts to have a choice of component variations.
In this case, I would create a mixin `entries-list--compact` inside the entries-list Sass file, which would contain CSS properties that would make the entries-list smaller.
Back on in the index Sass file, I would include that mixin:
I've found this pattern of mixins to be very powerful. Any page can decide whether to use any mixin at any page-width. CSS for layout stays very lean, as the only properties it's concerned with 99% of the time is width, height, margin, and padding. A component can be completely replaced with new styles and behave properly on existing pages so long as it conforms to its existing "API" of mixins.
It addresses some of these points at 35:23 - that you can kind of make CSS work if you always do everything right, but it's not as easy in practice (most of the experience stuff is at the beginning - which shows that they did kinda do everything "right").
Because one is an extension of the underlying technology, and the other one changes the technology out altogether. I still believe CSS is a vital part of the web ecosystem, and we should work to fix the underlying issues rather than just try to work around it via JS.
I agree with you. I've done both approaches at scaled, and I'm still not really sold on CSS-IN-JS. Of course, I think it's a matter a taste (and maybe experience?) so to each its own.
Personally I much prefer using separate css (or sass) file, one for each component (assuming you also have a "layout" component for shared styles) and import each relevant css file as a module.
This way you keep writing our CSS out of your JS, but still can keep it scoped to your component. It's also obvious what css a component uses, and each to grep for when you want to delete some css.
I take issue with your assertion about how IDs "are intended". I think that idea (and CSS being taught that way) is one of the reasons people have trouble with CSS.
There are quite a few reasons for preferring to not use IDs, here's two:
1- specificity of IDs always trumping things
2- having to change it from an ID to a class later on if it becomes a reusable item (which in a widget, is almost always the case). There is no reason a class cannot apply to just a single item, where an ID is by its nature limited.
All three of the points raised are just dismissing the root of the problem and offering a "solution" using plain CSS classes that relies on everybody following some bespoke convention to work around the problem rather than addressing it head-on like CSS-in-JS solutions do.
1. and 2. attempt to address the lack of modularity in CSS through convention when you can have guaranteed modularity through auto-generated CSS classes that are content-addressed and thereby globally unique by definition with CSS-in-JS. Not to mention you can use a real module system for sharing styles instead of being limited to sharing variables through some global context, which again opens up the possibility of name clashes.
3. recommends a solution for dynamic styles based on yet another CSS feature that relies on global namespacing, and then a fallback based on string concatenation that can't actually address all dynamic use cases. Then it goes on to dismiss the use case entirely, when in a single page application, all styles are inherently dynamic based on the state of the components that are currently being rendered, which is why there's such a painfully obvious impedance mismatch when implementing anything that's truly dynamic using CSS classes, when you have to resort again to concatenating lists of static classes together rather than mapping state to styles directly like you could with CSS-in-JS.
Of course, I'm not saying those approaches can't work at all, nobody is saying that. You can obviously make them work, and people have used those approaches for ages before CSS-in-JS came along. But using the existence of those approaches to dismiss a different approach that tangibly addresses the inherent flaws of those approaches doesn't feel like a particularly compelling argument.
Yes, it's dismissing the root of the problem because I am not convinced the "cost of doing CSS" is enough to justify moving to something like CSS-in-JS. Again, as I said above - it's a strong opinion, but weakly held - given enough evidence, I'd reconsider my position.
My point with the examples I gave was just to show that it's possible to handle the issues the author wrote about. I'd prefer to see efforts to fix the issues in CSS instead of discarding it completely in favor of a JS solution.
I'm not saying I can specify how to "solve" CSS issue in a couple paragraphs. As regards #3, that's specific to the kinds of dynamic styles I find most often in web apps. Very rarely do I see styles generated dynamically where it isn't effectively a choice between a couple of options (in my experience, of course). And when you do, you can just write out styles from the JS into the template (and I've definitely done fully dynamic styles in that way when it is necessary). Dynamic styles would be a place where I could see a fit for CSS-in-JS, btw.
The global namespacing this is something I believe is being worked on in the CSS Modules specification, but again, that is really easily solved. I can say loading external libraries can mess that up (i.e. Bootstrap and the ilk).
I don't care what people use, I'm glad the argument is what the author (who co-wrote the styled components lib) was what he liked. But I am really concerned that some proponents promote their way as the only way forward. Personally, I haven't found a situation yet where CSS-in-JS would materially benefit the application over a careful, convention-based approach. And I want to make sure people know there are other options that work.
The down-side with this is very high coupling between UI logic and style.
If style becomes out of fashion, you have to modify files that contain logic. If framework (react/vue) becomes out of fashion, keeping styles will be difficult.
The other down-side is thousands of web developers having to re-learn CSS and the tooling behind your app instead of just changing CSS files.
In practice, I think a lot of people have found that you can rarely do a complete overhaul of a website’s design using only CSS. Even if you could, it would be impossible to feel confident that your changes look reasonable across all uses of said CSS. So if you’re doing a big redesign you will usually have to work with logic anyway.
I think there’s truth to your second point though - reusing styles in parts of a project that does not use the same framework. Something like Tailwind CSS can be a good option then.
> you can rarely do a complete overhaul of a website’s design using only CSS
Full design yes, but branding/theming is much easier if you use an external styling framework like Bootstrap 4 or Foundation and use their component and utility classnames.
We have a 300+ page app and tried the one stylesheet per component thing with theme and layout all combined in the past, and was a huge mistake.
Banning most custom CSS in place of using the Bootstrap component and util classes has been so much easier.
Your styles are coupled to your UI logic anyway, even if you go out of your way to make them implicit by separating the CSS and JS into their own files. It's better to have the relationship explicitly defined in code instead of hiding it. That's the whole reason why CSS sometimes breaks in unexpected ways: you fail to realize the implicit coupling of the styles and the UI logic, so you fail to reason what changes need to be made both to styles and the UI logic to make your change.
Ok, but, the average startup web dev stays at a company for like two years? And then the thing eventually gets rewritten anyway in the latest flavor of the week, because nobody is using the same tools as two years ago.
I guess the concern for longevity most devs have is amusing when most software, if its not like systems level stuff, or problems most devs dont want to solve, tends to get disposed pretty frequently.
By the way, most of the software that actually sticks around was written in C and generally solves a problem most people wont tackle. Like zlib or sqlite or nginx or the linux kernel. You can almost pretty much judge the longevity of a piece of software based on how hard the problem it tackles is. Like encryption or compression? Those libraries are going to be around forever, because how many coders do you know that can write a semi compitent encryption library? And how manu coders can write a templating engine?
Like most of web dev is throwaway code. It just is. Arguments based on like "will they be able to restyle it in 10 years?" Well are they even going to be around?
Absolutely. But im not sure "bad code" is the same thing as code written for a purpose at a particular time. I think something can be good code if its lifespan is understood in the context of the business goals. I just get cynical when I hear people apply these principles to something that may live five years. Not every project is going to be maintained for 30 years
You don't need to use different languages to decouple things. A common pattern in React is to decouple logic and style using presentational components and container components (there are lots of articles on it if you Google those two terms), and I find that split to be much more natural than trying to split up HTML, JS, and CSS (which often need to cooperate with each other). One good practice with CSS-in-JS is to only use CSS in presentational components.
If you're building a complex UI that uses components as a cohesive library, there will always be some coupling. Even with the classic bootstrap example, once you've built an application and introduced any number of third party components, it gets messy to change things.
Better to have a cohesive set of theme/rules and get them to work together as best possible. I've been a big fan of material-ui and react-jss and is imho about the best option I've used in over two decades of working on web based applications.
This is a requirement that most sites can simply dismiss these days. The distinction between an app and a website is blurry, a lot of interaction simply works far better with Javascript.
Supporting "no Javascript" can be costly. It's possible with server-side React and careful engineering, but why bother? What's the impact on the business?
I don't know what the real impact is, but if your site shows me blank page without javascript(I have it off by default) I am closing the tab.
I don't think supporting noscript version is costly because for me that's how it supposed to be by default. 90% sites that are currently on the internet would work just fine without any js and 95% would work with as little as hackernews has. Modern CSS allows to create most of the experiences and unless you need some interactive forms or serving live broadcasts, games etc., there's just no point in using javascript.
Over the years I've stripped javascript from about 40sites which I visit daily without sacrificing any real functionality. Those sites download and render visibly faster, only relevant cotent is shown and I even implemented dark theme for them. My only javascript fixes are for broken galleries or embedded videos (and those wouldn't even be necessary if developers wrote a fallback to noscript).
It used to be that developers loaded many little scripts so I could only block the useless crap but since everything is minifed and bundled in one huge unreadable file, I just use uMatrix to block it entirely and Stylus and Tampermonkey to fix it.
I've been using elm-css on a project lately. Pretty cool with typesafe CSS. Also inline, but since everything is functions it's easy to compose/reuse as well when needed. (Compared to the string templating shown in this article)
Just put your CSS in a .css file where it can be cached, delivered by CDNs and can easily be edited in a single place.
Separation of content and presentation has been around for a good reason. One should always avoid mixing logic and design because it will break some day, no matter how well you think you handle it.
> Just put your CSS in a .css file where it can be cached, delivered by CDNs
.js files are cached and delivered by CDNs too.
> can easily be edited in a single place
If you change the name of a class (or add a new one, delete another one, edit the structure of the component, etc...), then you have to open and edit 2 files. With author's solution you don't. The CSS is collocated with the component.
> Separation of content and presentation has been around for a good reason. One should always avoid mixing logic and design
Author is talking about putting the React component (presentation) and its CSS (presentation) in the same file. He's not mixing business logic and design.
If you need caching then you would likely server render your page and that would inline all of the critical css to be cached as well.
Writing your css in JS files also does nothing to prevent you from separating content and presentation. You can write components that just handle styling. I see more problems with separation in css where you end up with one giant file that handles the whole site.
We built a relatively large social media management platform, and for one of our major features (a streams page that shows social media activities from different sources), we put a lot of our css in JS including all the logic for stream sizing/resizing and page responsiveness. I can honestly say that this approach is terrible. It is a maintenance nightmare. Even the smallest changes require a ton of time. We're now rebuilding the page from the ground up because it has gotten so messy, no one on the team is interested in touching it.
> Why don't we have more : "We tried it, it is the worst, especially for products which lifespan is more than two months"
Because that last sentence is just rubbish, CSS in JS is great. I'm using it for large projects already 4 years. If your experience is bad you must be doing something wrong. CSS in JS is almost the same as working with (S)CSS, except for extra power to control dynamic elements without having to juggle with classnames.
Juggling pre-compiled gpu stuff (css classes) exists for a reason.
Scss is like css.
Jss is css + unnecessary abstraction on top of css + unnecessary memory and cpu cycles + writing part of css rules inside flow control (which can turn into js in css in js.
GPU facing languages have always been ugly and not just in this industry. But they are like that because of their nature. Making them friendlier is always welcome, but replacing them with cpu stuff defeats the whole purpose of a gpu.
> CSS in JS is almost the same as working with (S)CSS, except for extra power to control dynamic elements without having to juggle with classnames.
I completely disagree.
Time and effort creating frontend design systems, will result in a set of CSS files .. but will also enable efficiency, flexibility, accessibility, maintainability and extensibility. These qualities just aren't going to be as available if you use CSS in JS.
There's nothing expressly better about SCSS over CSS in JS that you have demonstrated.
CSS In JS is mostly using similar structure, but often the JS dom interface naming... so fontFamily instead of font-family. It's also far easier to introduce codified variant functions or variable injection in JS than it is in SCSS.
I'm not saying don't use SCSS if it fits your model better... I've been very happy using react-jss via material-ui ... I've extended the baseline theme and that gets used throughout the application with each component defining its' styles that get injected.
Sharing can be a little more awkward, but it's easy enough, just call the same style method(s), or extend the baseline theme that gets injected.
The only thing you mention that might be better with (S)CSS directly would be efficiency and even that's relative. You can absolutely do all the rest with CSS in JS.
There have been many philosophical (and practical) conversations over the years that have lead to the development of a rich and varied frontend development ecosystem.
If you're building a frontend system, you need to consider the overall (macro) view, as well as the detail oriented (micro) view.
It's very difficult to do this with CSS in JS because of the compromises that need to be made to work in this way.
At my company, I made the executive decision to drop CSS-in-JS because none of those libraries support PostCSS, and most have their own from-stratch, half-baked CSS transformation pipeline, not 10% as powerful as the PostCSS ecosystem.
I love PostCSS, and I'll happily consider CSS-in-JS again when somebody writes a library that doesn't try to reinvent the wheel.
I write CSS in CSS and my JavaScript in JavaScript because at some point abstractions pile up into this massive cognitive burden for anyone adopting your code, especially when they didn't follow the exact same path as you technology-wise or if they're newcomers. I want my work to be pick-up-and-play, not RTFM x 20 abstractions and tools.
Even if there was more cognitive burden, it's insignificant compared to the drastically reduced amount of context switches the developer has to deal with.
It's also redundant, goes completely against the features of CSS (the cascading part), doesn't utilize the possibility of selectors, children, etc, ugly, and computationally heavy.
Not to mention that it doesn't work without JavaScript enabled on the client (unless he's generating CSS in server-side JavaScript). That's fine for a true web app (and web apps do have their place), but it's completely not fine for a web page, which should display just fine without JavaScript.
People should not be forced to grant you permission to execute code in order to read text & view images.
CSS... sweet memories. For some reason I never was able to learn how the damn thing works. I worked for Google Analitics in 2011 and we rebuilt it using new in house built framework which championed an idea of a separate styles for an on screen component. Every dev was starting a new component with: clean_styles directive as nobody was brave enough to deal with what comes from the top. Even though it was possible to use cascading part, nobody was brave enough to own styles for the whole product. So, We ended up with so many styles we had to split them in couple files as we reached a limit in IE on number of styles in one file. Last time I checked GA is loading 3 of them...
Is it a time for some other way of doing it?
I didn’t say I did not spend time, I said - could not. Same applies for most people in the team. I think we had coupe folks who were spending a lot of their time explaining CSS.
My theory is that CSS was something that was treated as a task. Make a lot of client/server side development and then make these freaking lines align perfectly. So, most of time engineers were avoiding styles, applying them was the most tedious and hated part of the job.
I agree with you re: the task comment, there is a difference between JavaScript developers and Front End UI developers. It's almost like the full stack discussion but just in the front end ecosystem.
They significantly overlap, so wouldn't say they are different. I would suggest that most "JavaScript developers" in the box you'd put them in are backend developers that only know a minimal amount of JS and don't really know JS well and by extension the browser itself.
And these are the same types who take on JS tasks without really knowing JS (or the DOM), writing what is often layers of garbage JS with extensions, addons and jQuery in what could have been 5-10 lines of JS.
I don't claim to be an expert on the DOM, and I might be close to expert in JS itself... there's something to be said for knowing at least enough to know what is possible and what to look for BEFORE working around a problem and introducing a bunch of crap.
I am one of those that knows CSS well enough and still chooses JSS, as imho it's easier to coordinate a set of theme values and configuration across a project. IMHO react-jss and material-ui do things VERY right in terms of what works for not only components, but a larger project.
For one thing, it's not CSS in Javascript... there's no cascade and no sheet, so it's just "styles in Javascript". (And, actually, this article is only about a specific implementation.)
The benefits listed are:
- "confidence" - but I think that's a matter of understanding and mastering the tool, whether it's CSS or this library. As the co-creator of "styled-components" the author is no doubt a master of it. For for the general developer, perhaps a roughly equal effort would provide a similar level of mastery in each. So why not invest in the standard?
"Painless Maintenance" - I would have to use it deeply before I could say too much about this. But I would guess that the danger of creating spaghetti code and a spaghetti of .css are pretty much the same and have the same root causes.
"Enhanced Teamwork" - I don't see the connection here. The discussion in this section seems to be about mastery of the tools again. The team can learn how to manage styles though CSS-based techniques or they can learn through techniques based on coding Javascript and the capabilities of this library.
Not that CSS doesn't have its issues. IMO, it's too low-level to use directly for many cases. There are two main problems:
(1) missing the tools to manage complexity, like scoping, variables, and modules. (2) allows you a lot of freedom to do bad things. But there are libraries that address these that don't throw out the fundamental design of CSS, as styles-in-code does.
To me it seems like a better approach to build on CSS to address its weaknesses rather than throw it out.
The design of CSS itself came out the recognition that the tight coupling of style and content has drawbacks, and this is signing back up for those drawbacks. And you better neatly divide your presentation code from your business logic code and data access code or you'll get all that coupled tightly as well.
I'm not dismissing this out-of-hand -- I haven't dug into styles-in-code approach so I don't have a deep understanding of it.
But I'm not convinced it's worth the time to look more closely at it. Really, not even close.
> "Painless Maintenance" - I would have to use it deeply before I could say too much about this. But I would guess that the danger of creating spaghetti code and a spaghetti of .css are pretty much the same and have the same root causes.
But as you pointed out, there is no cascade and no sheet. The styles apparently just apply to the stuff they are near in the code. No twisted logic to unwind, hence no spaghetti.
The potential problem I could see is that changes which would have been easy with a cascade would require lots of changes to copypasta in this approach. Like, "take the spinach out of this ravioli and replace it with mushrooms." Everything is scoped properly and the task is obvious at a glance-- it's just annoying.
> But as you pointed out, there is no cascade and no sheet. The styles apparently just apply to the stuff they are near in the code. No twisted logic to unwind, hence no spaghetti.
Ah, well, things are not that simple.
In a project of any complexity at all, the style of any individual element is typically dependent on a number of things which collectively make up the context of its presentation. E.g, the site theme, the component, and the individual element (at least -- usually there's an app-subsection and components are usually grouped into modules, etc.).
Note that this is inherent to the problem space and is true whether you're specifying styles in code or styles in cascading style sheets or any other way.
CSS provides a basic mechanism for dealing with this -- the cascade (though as I mentioned, IMO it is lacking some necessary features). Styles in code needs an answer as well.
If you were to simply hard-code styles at the element-level (which you can do using either mechanism BTW though its probably easier with style-in-code), you'll have a hard time finding all the places in the code you need to update if you want to make a change. You'll be doing a lot of full code searches, reading code, and trying to put yourself into the mind of the person who wrote the code in the first place.
The "spaghetti" in the metaphor are the lines of dependencies. We have spaghetti code when those lines are disorganized, entangled with irrelevancies, obscured, and otherwise unnecessarily difficult to deal with.
In fact, if you hard-code a style on an element that is dependent on the site theme, app section, component module, and component, you'd be hiding those dependencies, which creates spaghetti code rather than avoids it.
Now, I expect most developers would naturally try to avoid doing something like that. I'm just trying to point out why style-in-code doesn't really help you avoid spaghetti code.
I've been doing almost the opposite - enhancing and extending valid CSS stylesheets by using JavaScript to define new features and functionality to be made accessible and usable by writing valid CSS.
The big idea being that CSS should be able to apply to _any_ HTML, no matter how it was created before it got to the browser. Many style-related tools integrate tightly into your framework or into one particular workflow but don't give you the flexibility you need to apply any styles to any website unless it happened to be put together with specific tools a specific way, but I don't think that provides enough flexibility.
As someone coming from a traditional strict separation-of-content-and-style background and now convert to Styled Components, CSS-in-JS felt unnatural to me when I first encountered it. The problems with styles in large applications are well known and I had a solid handle on them with BEM and other bits of tooling, namespacing styles to a particular React component to avoid collisions etc.
It took me helping my brother learn how to do web development to shake me out of that mindset. He's not from a traditional webdev background and he got quite far quite fast with React. When he showed me his code, I noticed he was inlining all of his styles in his relatively small React components. I was going to explain why its bad practice to do that, but when you're building small almost atomic components, that approach actually makes a lot of sense, its what the BEM methodology tries to do albeit in a poorer way. CSS-in-JS tools like Styled Components preserve the spirit of this approach and minimise the downsides.
I think CSS-in-JS lends itself quite nicely to atomic design. At my current company, one of the first things we did was build a component library of atoms & molecules that are shared across many applications, keeping our design language very consistent.
We also make heavy use of Styled Components' theming capabilities, so we wrap our React apps with a ThemeProvider and give it an object with theme variables that drive the look and feel of our components. This is super useful when you have to support whitelabeling like we do, but even if you don't, its nice to keep your mystery-meat colors and spacings all in one place similar to how you might with SASS.
One of the gripes a lot of people have with CSS-in-JS is portability, and while that is a drawback, I feel it's an anti-pattern to rely on shared CSS styles to enforce design consistency across many deployables. It's kind of a classic case of developers trying to solve a process issue with technology, which is admirable, but from experience styles go out-of-sync with eachother quite easily and its rare that you can drop a CSS file into another project and have styles just work without having to do rework, so the benefits of sharing CSS rather than writing new styles off a styleguide are marginal at best. Again, this is all my subjective experience, your mileage may vary.
We still have a couple of issues with Styled Components, no technology is perfect and SC is still relatively young, but so far the pros have far outweighed the cons to the point where none of us really feel the itch to go back to SASS or plain CSS. I'm definitively not a magpie developer by any stretch, I'm usually resistant to change for the sake of change, but CSS-in-JS makes a lot of sense when you use it how its intended
styled-components is not popular on HN it seems. Allow me to share my own positive experience:
I have built websites in a variety of different ways, with a variety of different CSS schemes. I've worked with SASS, LESS, BEM, every major css framework, in both SPA and SSR environments.
I have also built react SPAs with the above variety of CSS schemes, as well as CSS-in-JS libraries like Aphrodite and Styled Components.
I currently build and maintain a medium-to-large web app with a small team, right now ~200 components, 31k lines of js including test files.
Styled Components has been an immensely positive experience for us, and i would not want to use any other way I have mentioned, or has been mentioned in this thread, to manage our styles in our app.
The reason why is because of the simple fact that it allows us to think of our styles just like any other component. We do not need a separate way of managing styles that we need to keep track of, whether a style is used is 100% the same as whether a component is used or not, which makes eliminating dead code, dead styles, easily managed through tooling.
It allows us to define simple, semantically-named components like <FlexGrid/> and <BigButton/>, and allows us to compose these components together to build up styles just like any other react component.
Styles are easily overridden from their parents. We use Ant Design for our UI toolkit, which does not use Styled Components, but any styles we want to override, as well as styles in nested classes, are easily done by wrapping an antd component. All the parent component needs to do is accept a "className" property. This makes interop with other components simple.
Effectively what this means is that after awhile, we get to live in a world where I can add a component into any given part of application, and be very certain its going to look and behave the same way it does in every other part of the application. When I'm building new features I don't want to think about styles, except when adding styles is part of the feature itself. Styled Components is the only way so far I've found that does that sufficently.
Globally-available CSS is great for web pages, but not so much for widget-based GUI web apps, which creates leaky abstractions. Most ways of managing CSS are systems to get around that, or treat it as a feature.
In short, 10/10 would use again, even over other CSS-in-JS libraries like Aphrodite. Note this opinion is scoped purely to react apps. Vue's approach seems appealing as well but I have not used it before, but to be honest I do prefer being able to have everything in JS or JSX, but thats a different discussion.
I hated styled-components when I had to use it. It introduces a ton of unnecessary nesting and weird abstractions just to give devs something that is superficially similar to something they are familiar with. I keep it simple with styles in JS.
Be very aware that most popular CSS-in-JS libraries (such as JSS) will completely break CSP (Content Security Policy). The default reaction is usually "Just allow unsafe-inline in your CSP header", but this is dangerous advise as it will disable CSP! I've even seen 'experts' advising to use webpack to set a static value as a CSP nonce during build-time...
If you want to use CSS-in-JS, you'll either have to use server-side rendering to inject CSP nonces in your index.htm [0], or set up a complex build system to extract the CSS from your JS so you can serve them as .css files.
Using server-side rendering to inject nonces into your single-page client side rendered webpage is such an ugly hack. I'd prefer the second solution but I have not been able to find a solution like that, nor do I have the time to dive into the webpack rabbit-hole to do so.
Why is it that whenever anyone posts anything about React, there's a horde of Vue users trying to convince us that they are doing it better? It feels a bit desperate.
The great thing about React is it is purely JS (or JSX, which is effectively a macro for the underlying JS). Which means it is explicit, and predictable. Perhaps that means there's less sugar, but any sugar and magic comes at a price.
I'm going to have a look at Vue more anyway, out of curiosity, though.
Edit: I note that some of the anger at React has been "Why does it need Redux/MobX if it is so good?". But Vue has Vuex to solve the same problem?
Story of my life as a front end developer... you can invent an abstraction to make life easier and simultaneously increase code size and complexity more than 10 fold. Easy is often an anti-thesis of simple.
Basic front end code isn't that challenging, but it does take some actual practice (not half-ass practice followed by a million poorly considered short-cuts).
Well I did spend this weekend trying figure out how to dynamically update keyframe rules with JavaScript only to discover the window.CSSKeyframesRule API is incomplete on most browsers so I found a different nonstandard way to solve that problem cross browser. I have not seen a failure to implement standards like that in many years.
Just about everything else on the frontend is absolutely solid cross browser with 5+ years of thoroughly tested support. People don’t write abstractions to fix weak technology, they do it to fix weak developers.
254 comments
[ 2.9 ms ] story [ 277 ms ] threadIf you do not server-side render, it does not matter whether you put your CSS into JavaScript or not—your JavaScript app is not going to render anything anyway.
By knowing how the sausage is made, I'm also aware that the line marking the aforementioned certain point is often drawn too early, at informational (i.e. document) stuff where HTML and CSS are fully capable on their own.
In fact, JS is extremely useful in the browser. It adds to the richness and interactivity of webpages. We must collectively appreciate this, and stop denying this! Even HN is a better experience with JS.
Some sites do give JS a bad name, and poorly used JS is something I hate too, but JS as a concept is something that I wholeheartedly support. Thankfully, the web is mostly opt-in - if you don't like the way a site employs technology, just don't visit it. Simple.
Slow internet connections are a reason to think about the experience when loading JS is slow and/or failed. It's not just 'poor people' who have slow internet - 'rich people' on inflight wifi or on the internet on the train can result in things not loading.
Ok, we do assume that you have visited our webpage at least once in an area of strong signal, however, once you've done that, all the JS is cached and all we transmit back and forth are lightweight, gzipped json payloads, often less than a kilobyte.
I use my own PWA regularly, and found it actually quite usable in-flight.
It's rather easy too if you're using a (great) library like styled components - this functionality is built in and just works with a couple of extra lines of code.
The deeper question here is will the app work at all without JS. That's quite hard to achieve (every client side interaction must have a server rendered equivalent accessible via a url or url params, essentially) but the CSS part is easy.
NoScript users are like the customer that demands the most but pays least. After some rants of such customer, they're ignored.
- In your react example, I see you created <Title> as styled.h1, but that's an awkward way of bootstrapping a component. Even if I used SC, I would still put the style information outside my component code in the same directory. At this point I don't see the benefit over doing something like:
What can SC do that regular CSS or SASS can't?How do you deal with mobile, where sometimes I have to override dozens of declarations with media queries?
- This ties into a broader point of having "style components" like <Grid /> and <Row />, which is a very nice way of working in React. styled-components (the library) simply takes that pattern and enforces it across your application. See style-components.com for links to some more resources about this pattern!
Instead we have used CSS Modules (https://github.com/css-modules/css-modules), first by including it manually in webpack, now it's already built into create-react-app so I just have to install node-sass and call my Sass files ComponentName.module.scss and I can use them the same way in my .tsx/.jsx files that you use CSS-in-JS. IMO that's a lot less messy and makes your jsx files smaller and better to read. Also it's easier to write Sass and have the pros of that language on top.
Did you consider this approach at all and what did you not like about it?
Having some experience with CSS Modules myself, I thought they were interesting and definitely an improvement, but still left a lot to be desired.
For example: needing to use a helper like `classnames` to join/toggle many dynamic classes together was very ugly and cumbersome. There is also no way to "directly" tie variable state/props to CSS rules – you're still required to use this indirection where a state/prop relies on there being a predefined class/modifier in the CSS file.
e.g.
With solutions closer to the "fully JS" end of the spectrum like Styled Components, there are no extra "modifier" CSS selectors to come up with to handle the above situation.RDD (resume driven development).
Cargo culting.
Ooooh shiney!
"I'm not confident enough to make my own decisions, so I'll let the 'community' decide for me."
Others (I'm thinking Angular and Vue) have their own templating systems that they compile to JS anyway.
Personally, I find the Vue.js concept much nicer, but even given that, I define my styling in LESS (SASS...) to benefit from inheritance/mixins on the level of styling. Semantic approaches like BEM or Bulma make a lot more sense to me.
It seems to me React has made a feature out of a flaw, much like the intermingling of code and HTML back in the days with ASP/JSP/PHP.
Look at this beauty for comparison: https://vuejs.org/v2/guide/single-file-components.html
https://vue-loader.vuejs.org/guide/scoped-css.html#scoped-cs...
Inspect the result here: https://codesandbox.io/s/3v0pjzoy7q
What language are you talking about? React is Javascript
> Look at this beauty for comparison
Meanwhile Vue is neither HTML [1], nor strictly speaking CSS [1], and has a very wierd concept of how objects work in JS.
[1] It's a templating system with its own rules and mini-DSLs that ends up being compiled into JS.
What is so weird about it? I personally find Vue vastly more approachable than React is, especially once you have to start writing all the plumbing to get all the libraries you need to go along with it to write a real world app.
> ] It's a templating system with its own rules and mini-DSLs that ends up being compiled into JS.
Vue has the option to use Webpack to compile html compliant templates to JS functions just like JSX (which BTW is not JavaScript and not HTML compliant and is also a separate concept that needs to be learned as well.)
CSS is just another add-on through Webpack when using Single File Components. Nothing really ground breaking here except for the fact that it creates a nice separation of concerns. This is especially true on teams with junior devs or designers. Or with a team that works on a site with mixed MPA and SPA features.
I go a bit in depth here: https://news.ycombinator.com/item?id=17471199
> Vue has the option to use Webpack to compile html compliant templates to JS functions just like JSX
Vue's templates are not HTML-compliant. They are just that: templates. That get compiled to JS anyway.
> JSX (which BTW is not JavaScript and not HTML compliant and is also a separate concept that needs to be learned as well.)
JSX is a very thin DSL on top of Javascript. It's just function calls: https://reactjs.org/docs/react-without-jsx.html
Once you understand that, everything falls into place.
> CSS is just another add-on through Webpack when using Single File Components.
It's not a webpack add-on. It's a part of Vue's templating engine that is essentially CSS-in-JS, they just give you a template to work in.
I've read this before. Vue is a framework. It also has a templating system that is not JavaScript, it's valid HTML with attributes that tell Vue how to bind to it. It's really not that difficult.
> Vue's templates are not HTML-compliant. They are just that: templates. That get compiled to JS anyway.
Sorry, but you're wrong here. They are valid HTML.
https://vuejs.org/v2/guide/syntax.html
"Vue.js uses an HTML-based template syntax that allows you to declaratively bind the rendered DOM to the underlying Vue instance’s data. All Vue.js templates are valid HTML that can be parsed by spec-compliant browsers and HTML parsers."
> JSX is a very thin DSL on top of Javascript. It's just function calls: https://reactjs.org/docs/react-without-jsx.html
IMHO only the simplest of components featuring JSX that don't read like a spaghetti PHP coding nightmare to me. For the small number of times you actually need the full power of JavaScript you could also use JSX in Vue with a render function if necessary. I personally prefer to keep my templates and logic separate when possible.
> It's not a webpack add-on. It's a part of Vue's templating engine that is essentially CSS-in-JS, they just give you a template to work in.
No, it's not part of the template engine, it's part of vue-loader which is used by Webpack to create single file components.
https://github.com/vuejs/vue-loader
You mean it has at least three JS-like DSLs (which are not JS, and have different rules depending on which context they are in). In addition it has a very weird binding system which I described at length in the linked comment.
Yup. "Not that difficult".
Meanwhile JSX is a single consistent DSL that directly maps to function calls:
That's it. Even "html-like" attributes that people seem to not like... are exactly what HTML attributes are in actual Javascript DOM APIs [1] [2]The amount of custom attributes, custom DSLs and gotchas just in the "HTML" part of Vue is staggering in comparison: https://pbs.twimg.com/media/DbVEoKOX0AEEen6?format=jpg&name=...
And funnily enough it ends up being compiled to what React is in the first place (here's the output of a Hello World app in Vue):
Look, it's exactly what React without JSX is [3]. Only in React you don't need to invent a custom scripting language and binding rules.[1] https://developer.mozilla.org/en-US/docs/Web/API/Element/att...
[2] And I'm really sad to see React team seriously discuss caving in to mob and considering replacing className with class etc.
[3] https://reactjs.org/docs/react-without-jsx.html
The attributes / DOM properties in JSX are also a mixed bag and not consistent. See https://github.com/facebook/react/issues/13525#issuecomment-...
> Look, it's exactly what React without JSX is [3]. Only in React you don't need to invent a custom scripting language and binding rules.
JSX is a custom extension to JavaScript. It's not part of JavaScript or intended to be part of the spec or implemented in browsers. In fact, you have to use some sort of transpiler in order to use it. So, it's not just JavaScript.
> https://pbs.twimg.com/media/DbVEoKOX0AEEen6?format=jpg&name=....
There's really nothing that complicated in here, if you're familiar with Vue. In fact, it's really easy for me to see what's going on at a glance in one place, which is my personal preference. From my own experience, that's rarely the case when working with React the way JSX tends to get broken up because it doesn't have something as simple as a standard if conditional statement within JSX itself.
I've never claimed you do not need to learn anything when working with Vue templates, you need to understand how the system works, but it took me all of a few hours to understand. The features and benefits that I prefer over React/JSX make that worth it to me.
Yes. However, one thing you fail to see is that it directly compiles to function calls.
is Which means:- you have access to JS variable in scope
- you can use JS facilities (proper if/switch statements, for loops, functional programming, you name it)
- you need no additional scripting or templating features. It's, well, just Javascript.
However in Vue (emphasis mine):
> There's really nothing that complicated in here, if you're familiar with Vue.
Yes. Exactly. If you're familiar with Vue
So:
- custom tag attributes: v-bind, v-if, v-for, v-on, v-show, v-model... (I honestly don't know how long this list is)
- custom attribute shorthands: :key, @key
- attribute extensions: v-on:keypress.prevent
Inside attributes you can have:
- Javascript expressions (much like React inside {})
- or magic binding:
- or JS-object-like magic bindings which resolve to a string: - or JS-array-like magic binding that gets resolved to a string: - or a magic array with objects that gets resolved to a string: - or a separate DSL for v-for: - or a separate DSL for v-for where you can bind entities from the DSL (which looks exactly like the magic binding to data from the component, what happens when they clash?): - or JS expressions that may be function references that may be things that look like function calls but actually aren't: - with special magic variables - with special magic modifiers "It's not that difficult" ©™ And the list above doesn't include the overview of the JS code that underlies components in view. It's another whirlwind of magic and non-magic: https://news.ycombinator.com/item?id=17471199Oh yes, and this gets compiled down to some JS that bears little to no resemblance to original code.
And somehow people complain about how React is difficult. Wat?
I understand how JSX works, stop patronizing me. The only thing I fail at is seeing how any of your examples are complicated or have magic so deep that you need to continue to burn Vue at the stake for. In fact, I find your Vue template examples completely intuitive and easy understand with minimal time invested in learning how Vue templates work. It's my preference to spend a little bit of effort up front learning how Vue templates work in order to have clearer separation between business logic and templates.
It's regular CSS in the templates and regular CSS in the frontend. There's no JS involved anywhere, unless you count the tooling, but we already use JS tools for CSS processing (PostCSS).
Scoped CSS is an old HTML5 feature that was dropped in favor of style encapsulation using Shadow DOM/Web Components.
It means you can't abuse JavaScript everywhere, creating totally unreadable render function, nest array mapping in Ternary operator and reduce it to what the hell no one can read and destroy all the readabilities.
For me, for you, for everyone, if you using that syntax, then it is simply readable just like html.
Less powerful, but the management definitly worth more.
The problem with all templating systems is that they start with "we need to limit the amount of logic". But all templating systems find out that this is extremely limiting. So they grow. And grow. And grow. And grow.
Same with Vue. The amount of special cases and custom things just grows and grows. See my comment here: https://news.ycombinator.com/item?id=19199423
You need simple conditional logic. So you end up with v-if and v-else. Then you have to add v-if-else.
You need loops. So you end up with a custom DSL for v-for. And then you expand it to also work on objects. And you need to bind to object produced inside the for loop. And...
And you need to handle events. But events are anything but simple. You need to prevent them, you need to stop or start propagation, you need access to their properties. So you end up with v-on:click.stop.prevent. And function calls. And magic variables in the form of $event.
Worse still, all your existing knowledge about how to apply these concepts in JS is void. Template has taken over.
So in the end you end up with a system that is not really HTML, not really JS, but a weird combination of the two. And the amount of concepts is not exactly more readable than plain React that just uses JS everywhere.
https://vuejs.org/v2/guide/render-function.html
With its own syntax. Which looks like HTML but isn't.
It's actually an XML abstraction that closely resembles HTML + JS-DOM, and is then converted into function calls and arguments.
It's also about as close to E4X as an abstraction that I've seen and something I wish was cross browser over a decade ago when it was first introduced by Mozilla and Adobe, but that's a long side-track. In the end, it's very effective and works well imho. Yes there are some more complexity points in some places, but I don't think anything else does it better. Vue imho is comparible, but I don't like it as much and I feel that Angular is far worse in practice.
Vue Templates are a very thin DSL on top of HTML. It's just markup.
Once you understand that, everything falls into place.
Add in Tailwind utility classes and you've got a great design system that can be built on the fly with consistent standards.
Where is template getting assigned to the code inside the script tag?
Does OtherComponent somehow mysteriously map to other-component? How does one pass arguments to it? Is a .vue file actually HTML or is it parsed somehow to be HTML?
The thing I like about React is the explicitness of it. This is a source code file that exports component X. Component X uses style Y as defined above because it's explicitly passed in as a prop, etc etc.
It's definitely a limitation of certain CSS-in-JS implementations, but unfortunately one that inherently comes from "using the platform."
https://rafaltomal.com/tips/save-css-chrome-inspector/
https://www.styled-components.com/
I'd rather have libraries focus on one thing and do it well - the Unix philosophy. This lets me compose the appropriate libraries for the problem at hand.
https://vuejs.org/v2/guide/single-file-components.html
With regard to media queries, it depends on the library. For the library the author is using, the media queries are defined inline: https://www.styled-components.com/docs/advanced#media-templa...
With SASS, I find it really convenient to define variables for common/brand colours, for example.
Almost all CSS-in-JS solutions (including styled-components mentioned in the article) still support pseudo selectors, media queries, etc.
1- append only? No, each module/feature/widget gets its own CSS file, imported to the main app CSS file. Delete the widget? Delete the file.
2- Specificity issues? Never use IDs, stop using tag names and simple classes and adopt a simple naming structure (doesn't have to be BEM, it could literally be ".widgetName-header")
Since I adopted those 2, I've almost never had dead CSS from deleting features or collisions in my CSS. I do still have a small base set of styles that are shared but it's small enough to be easily manageable.
3- dynamic properties? CSS variables. Not an option? Child classes that apply the dynamic styles serve most use cases. Truly dynamic styles are rare, in my experience.
I'm still keeping an open mind about the possibilities, but my strong opinion (weakly held) is that I still don't see CSS-in-JS as more of a bandaid for people that like CSS and (for many, not all) those that don't have an in-depth understanding of it.
http://getbem.com/
Each component has its own folder with its own css file and each rule starts with .name-of-the-component.
For dynamic properties, we either create conditional classes (e.g. 'success', 'error') or pass the rules through 'style' (e.g. dynamic height).
For dynamic themes, we create an object at the root of the app
Then pass it down to the related components That being said, I tried styled-components once and don't really have negatives about it. It's a viable option.This rarely happens. I would argue that creating an automated system to enforce "rules" should be favored over forcing every developer to know the rules and abides by them.
It is much easier to understand the relationship between css and js when the css is just a js variable.
Having built many large applications using the CSS file method, css modules, each widget gets its own file, co-locating css files with the js, I much prefer using `styled-components`. It provides a ton of flexibility, it opens doors for dynamic css by leveraging js (the hacks I've seen, had to write to get css dynamic is astounding), and I don't have to look very far to see how it's being used because the CSS is literally attached to the component I'm using. All I do in VSCode is cmd+click and bam, I can see the CSS for this component. There's no need for naming convention, there's no worry about global css variables getting into your styles, and there's no digging around looking for css that might be influencing your component. The best part for me is: when I delete the component, the CSS is gone as well. There's no thought put into scouring the FS to find lingering CSS that used to be used.
I love `styled-components` and most of the designers I work with also enjoy it.
Judge all you want, but you can only change technology, not human nature.
Good engineering is to find pragmatic solutions that work in the real world.
It's hard to know when you can delete a rule. Are you positive that all the rules in your component's CSS file only affect that component? Then great, delete the whole file.
What about the individual rules within that file? How do you know whether your app is still rendering any components with the `fancy` modifier anymore? Keep in mind any JS on the page could be be dynamically toggling the `fancy` class, including in very rare circumstances, including from dynamic data that might bring the string "fancy" with it so that you can't just grep your codebase for it. Is it safe to delete the `fancy` rule?
Another problem is that even BEM admits that sometimes nested selectors are necessary. It's right there in the BEM FAQ: "While in general BEM recommends avoiding nested selectors, in this case they are reasonable."
Sometimes you need your button to look a certain way when it's inside a nav menu item.
So what's the solution? Either a nested selector (targeting both the nav item and the button) or a new modifier on your button, like `is-in-nav-item`.
Eventually your app changes and you're not rendering any buttons in nav items anymore. Maybe nav items don't even exist anymore and you at least remembered to delete those. Are you also going to remember all the places in your code you need to track down to delete these obsolete nested selectors/modifiers? Or is there just going to be dead code now?
What if the selector is slightly more general, and you're not sure if it's targeting other things as well? Are you confident that you won't break anything else? CSS selectors are effectively global. Anything could be secretly relying on the styles that a selector applies.
That is the problem. Not deleting a file. Your individual component CSS files are now the "append-only" stylesheets, not necessarily the whole combined stylesheet.
Absolutely
The beauty of CSS modules over a convention-based approach like BEM is that you end up with cleaner, simpler CSS files -- with selectors like `.Widget .search.error` rather than `.Widget__search--error`. The downside is that there's a compilation step, but chances are that you already have _some_ sort of compilation going on -- even if just to bundle things up.
The way to handle "special" cases for buttons -- like when they appear in certain contexts -- is to allow the calling code to add a class to the button; a class which comes from the caller's own CSS module. Alternatively, use CSS variables:
Button.css
Nav.cssI have one exception to that in my own work, which is to only ever use IDs for styles that affect the layout of a block/component on a specific page. This makes sense since parts of a page layout are usually very specific and not that dynamic(in which case class names might be more appropriate). At the same time, component-level styles should never make assumptions about how they are positioned on a given page.
Let's say that we have a page `/blog/:entry_id`, and this page has a right-hand column to list related blog entries. This component would have an id `#blog-entry__entries-list`, which would control how the related-entries list appears on the blog-entry page(in this case, putting it in a column on the right), and a `.entries-list` class that controls the global appearance of the component.
This way, the entries-list can be used in different contexts without having weirdness caused by a margin working fine on one page but having to be negated on another page where the margin doesn't work. Try to add styles, but do as minimal overriding as possible.
In combination with BEM, primarily for the benefit of all selectors having the same specificity, I've found this separation of concerns between IDs and class names to be very powerful and simple to understand, especially since it doesn't require more verbosity.
Another part of my styling workflow is Sass mixins.
Let's say that we want the entries-list component to appear more compact on another page. Perhaps it appears somewhere on the site index, and takes up a little more room than we'd like.
Since component styles can't assume anything about their environment, and since layout styles(i.e. our ID selectors) can't know about the inner workings of their components, there needs to be a way for layouts to have a choice of component variations.
In this case, I would create a mixin `entries-list--compact` inside the entries-list Sass file, which would contain CSS properties that would make the entries-list smaller.
Back on in the index Sass file, I would include that mixin:
```
```But what if we only need the list to be compact at a specific page width?
```
```I've found this pattern of mixins to be very powerful. Any page can decide whether to use any mixin at any page-width. CSS for layout stays very lean, as the only properties it's concerned with 99% of the time is width, height, margin, and padding. A component can be completely replaced with new styles and behave properly on existing pages so long as it conforms to its existing "API" of mixins.
It addresses some of these points at 35:23 - that you can kind of make CSS work if you always do everything right, but it's not as easy in practice (most of the experience stuff is at the beginning - which shows that they did kinda do everything "right").
and suddenly
> I still don't see CSS-in-JS as more of a bandaid for people that like CSS
Why are SCSS or poor-man's-substitute-for-modularity in the form of naming conventions fine, and why JS-in-CSS is bad?
Personally I much prefer using separate css (or sass) file, one for each component (assuming you also have a "layout" component for shared styles) and import each relevant css file as a module.
This way you keep writing our CSS out of your JS, but still can keep it scoped to your component. It's also obvious what css a component uses, and each to grep for when you want to delete some css.
There are quite a few reasons for preferring to not use IDs, here's two:
1- specificity of IDs always trumping things
2- having to change it from an ID to a class later on if it becomes a reusable item (which in a widget, is almost always the case). There is no reason a class cannot apply to just a single item, where an ID is by its nature limited.
1. and 2. attempt to address the lack of modularity in CSS through convention when you can have guaranteed modularity through auto-generated CSS classes that are content-addressed and thereby globally unique by definition with CSS-in-JS. Not to mention you can use a real module system for sharing styles instead of being limited to sharing variables through some global context, which again opens up the possibility of name clashes.
3. recommends a solution for dynamic styles based on yet another CSS feature that relies on global namespacing, and then a fallback based on string concatenation that can't actually address all dynamic use cases. Then it goes on to dismiss the use case entirely, when in a single page application, all styles are inherently dynamic based on the state of the components that are currently being rendered, which is why there's such a painfully obvious impedance mismatch when implementing anything that's truly dynamic using CSS classes, when you have to resort again to concatenating lists of static classes together rather than mapping state to styles directly like you could with CSS-in-JS.
Of course, I'm not saying those approaches can't work at all, nobody is saying that. You can obviously make them work, and people have used those approaches for ages before CSS-in-JS came along. But using the existence of those approaches to dismiss a different approach that tangibly addresses the inherent flaws of those approaches doesn't feel like a particularly compelling argument.
My point with the examples I gave was just to show that it's possible to handle the issues the author wrote about. I'd prefer to see efforts to fix the issues in CSS instead of discarding it completely in favor of a JS solution.
I'm not saying I can specify how to "solve" CSS issue in a couple paragraphs. As regards #3, that's specific to the kinds of dynamic styles I find most often in web apps. Very rarely do I see styles generated dynamically where it isn't effectively a choice between a couple of options (in my experience, of course). And when you do, you can just write out styles from the JS into the template (and I've definitely done fully dynamic styles in that way when it is necessary). Dynamic styles would be a place where I could see a fit for CSS-in-JS, btw.
The global namespacing this is something I believe is being worked on in the CSS Modules specification, but again, that is really easily solved. I can say loading external libraries can mess that up (i.e. Bootstrap and the ilk).
I don't care what people use, I'm glad the argument is what the author (who co-wrote the styled components lib) was what he liked. But I am really concerned that some proponents promote their way as the only way forward. Personally, I haven't found a situation yet where CSS-in-JS would materially benefit the application over a careful, convention-based approach. And I want to make sure people know there are other options that work.
If style becomes out of fashion, you have to modify files that contain logic. If framework (react/vue) becomes out of fashion, keeping styles will be difficult.
The other down-side is thousands of web developers having to re-learn CSS and the tooling behind your app instead of just changing CSS files.
I think there’s truth to your second point though - reusing styles in parts of a project that does not use the same framework. Something like Tailwind CSS can be a good option then.
Full design yes, but branding/theming is much easier if you use an external styling framework like Bootstrap 4 or Foundation and use their component and utility classnames.
We have a 300+ page app and tried the one stylesheet per component thing with theme and layout all combined in the past, and was a huge mistake.
Banning most custom CSS in place of using the Bootstrap component and util classes has been so much easier.
So just put the styles in separate .js files and import them.
I guess the concern for longevity most devs have is amusing when most software, if its not like systems level stuff, or problems most devs dont want to solve, tends to get disposed pretty frequently.
By the way, most of the software that actually sticks around was written in C and generally solves a problem most people wont tackle. Like zlib or sqlite or nginx or the linux kernel. You can almost pretty much judge the longevity of a piece of software based on how hard the problem it tackles is. Like encryption or compression? Those libraries are going to be around forever, because how many coders do you know that can write a semi compitent encryption library? And how manu coders can write a templating engine?
Like most of web dev is throwaway code. It just is. Arguments based on like "will they be able to restyle it in 10 years?" Well are they even going to be around?
both of these are pretty bad examples, as several modern developments have surfaced in both cases - here are 2 examples
- https://wikipedia.org/wiki/Curve25519 - https://github.com/google/brotli
Better to have a cohesive set of theme/rules and get them to work together as best possible. I've been a big fan of material-ui and react-jss and is imho about the best option I've used in over two decades of working on web based applications.
Thank you!
Supporting "no Javascript" can be costly. It's possible with server-side React and careful engineering, but why bother? What's the impact on the business?
Which human right, specifically? Humans have the "right" to install a modern browser and enable Javascript.
> "Javascript" is costly too - but maybe not your concern since it's not a business cost.
Indeed, the cost you pay to run Javascript does not show up in my budget, just like I don't pay your ISP to serve my site to you.
I don't think supporting noscript version is costly because for me that's how it supposed to be by default. 90% sites that are currently on the internet would work just fine without any js and 95% would work with as little as hackernews has. Modern CSS allows to create most of the experiences and unless you need some interactive forms or serving live broadcasts, games etc., there's just no point in using javascript.
Over the years I've stripped javascript from about 40sites which I visit daily without sacrificing any real functionality. Those sites download and render visibly faster, only relevant cotent is shown and I even implemented dark theme for them. My only javascript fixes are for broken galleries or embedded videos (and those wouldn't even be necessary if developers wrote a fallback to noscript).
It used to be that developers loaded many little scripts so I could only block the useless crap but since everything is minifed and bundled in one huge unreadable file, I just use uMatrix to block it entirely and Stylus and Tampermonkey to fix it.
I can show you "this site requires Javascript" instead, but let's just say you're not part of the target audience and that's fine.
> I don't think supporting noscript version is costly because for me that's how it supposed to be by default.
That highly depends on the site, of course.
> 90% sites that are currently on the internet would work just fine without any js and 95% would work with as little as hackernews has.
99.9% of websites are not actually businesses that employ developers. If that's your standard, I agree. A simple webpage does not require Javascript.
Just put your CSS in a .css file where it can be cached, delivered by CDNs and can easily be edited in a single place.
Separation of content and presentation has been around for a good reason. One should always avoid mixing logic and design because it will break some day, no matter how well you think you handle it.
.js files are cached and delivered by CDNs too.
> can easily be edited in a single place
If you change the name of a class (or add a new one, delete another one, edit the structure of the component, etc...), then you have to open and edit 2 files. With author's solution you don't. The CSS is collocated with the component.
> Separation of content and presentation has been around for a good reason. One should always avoid mixing logic and design
Author is talking about putting the React component (presentation) and its CSS (presentation) in the same file. He's not mixing business logic and design.
Not in 2019, in the age of excessive A/B testing, where every page load gives you a different set of JS.
Writing your css in JS files also does nothing to prevent you from separating content and presentation. You can write components that just handle styling. I see more problems with separation in css where you end up with one giant file that handles the whole site.
Why don't we have more : "We tried it, it is the worst, especially for products which lifespan is more than two months"
Because that last sentence is just rubbish, CSS in JS is great. I'm using it for large projects already 4 years. If your experience is bad you must be doing something wrong. CSS in JS is almost the same as working with (S)CSS, except for extra power to control dynamic elements without having to juggle with classnames.
Or perhaps there's something to it, and the idea is not as good as one might claim it to be.
Scss is like css.
Jss is css + unnecessary abstraction on top of css + unnecessary memory and cpu cycles + writing part of css rules inside flow control (which can turn into js in css in js.
GPU facing languages have always been ugly and not just in this industry. But they are like that because of their nature. Making them friendlier is always welcome, but replacing them with cpu stuff defeats the whole purpose of a gpu.
I completely disagree.
Time and effort creating frontend design systems, will result in a set of CSS files .. but will also enable efficiency, flexibility, accessibility, maintainability and extensibility. These qualities just aren't going to be as available if you use CSS in JS.
CSS In JS is mostly using similar structure, but often the JS dom interface naming... so fontFamily instead of font-family. It's also far easier to introduce codified variant functions or variable injection in JS than it is in SCSS.
I'm not saying don't use SCSS if it fits your model better... I've been very happy using react-jss via material-ui ... I've extended the baseline theme and that gets used throughout the application with each component defining its' styles that get injected.
Sharing can be a little more awkward, but it's easy enough, just call the same style method(s), or extend the baseline theme that gets injected.
The only thing you mention that might be better with (S)CSS directly would be efficiency and even that's relative. You can absolutely do all the rest with CSS in JS.
If you're building a frontend system, you need to consider the overall (macro) view, as well as the detail oriented (micro) view.
It's very difficult to do this with CSS in JS because of the compromises that need to be made to work in this way.
I love PostCSS, and I'll happily consider CSS-in-JS again when somebody writes a library that doesn't try to reinvent the wheel.
tl;dr because it's convenient.
It's also redundant, goes completely against the features of CSS (the cascading part), doesn't utilize the possibility of selectors, children, etc, ugly, and computationally heavy.
But yeah, why not.
People should not be forced to grant you permission to execute code in order to read text & view images.
People not taking the time to learn is not a reason to throw an entire building block of the web out.
(Yes, I realize there are a lot of people who know CSS and still choose CSS-in-JS, but I'm specifically referencing the point re: not learning CSS.)
My theory is that CSS was something that was treated as a task. Make a lot of client/server side development and then make these freaking lines align perfectly. So, most of time engineers were avoiding styles, applying them was the most tedious and hated part of the job.
And it is hard to be good at something you hate.
I don't claim to be an expert on the DOM, and I might be close to expert in JS itself... there's something to be said for knowing at least enough to know what is possible and what to look for BEFORE working around a problem and introducing a bunch of crap.
I am one of those that knows CSS well enough and still chooses JSS, as imho it's easier to coordinate a set of theme values and configuration across a project. IMHO react-jss and material-ui do things VERY right in terms of what works for not only components, but a larger project.
For one thing, it's not CSS in Javascript... there's no cascade and no sheet, so it's just "styles in Javascript". (And, actually, this article is only about a specific implementation.)
The benefits listed are:
- "confidence" - but I think that's a matter of understanding and mastering the tool, whether it's CSS or this library. As the co-creator of "styled-components" the author is no doubt a master of it. For for the general developer, perhaps a roughly equal effort would provide a similar level of mastery in each. So why not invest in the standard?
"Painless Maintenance" - I would have to use it deeply before I could say too much about this. But I would guess that the danger of creating spaghetti code and a spaghetti of .css are pretty much the same and have the same root causes.
"Enhanced Teamwork" - I don't see the connection here. The discussion in this section seems to be about mastery of the tools again. The team can learn how to manage styles though CSS-based techniques or they can learn through techniques based on coding Javascript and the capabilities of this library.
Not that CSS doesn't have its issues. IMO, it's too low-level to use directly for many cases. There are two main problems: (1) missing the tools to manage complexity, like scoping, variables, and modules. (2) allows you a lot of freedom to do bad things. But there are libraries that address these that don't throw out the fundamental design of CSS, as styles-in-code does.
To me it seems like a better approach to build on CSS to address its weaknesses rather than throw it out.
The design of CSS itself came out the recognition that the tight coupling of style and content has drawbacks, and this is signing back up for those drawbacks. And you better neatly divide your presentation code from your business logic code and data access code or you'll get all that coupled tightly as well.
I'm not dismissing this out-of-hand -- I haven't dug into styles-in-code approach so I don't have a deep understanding of it.
But I'm not convinced it's worth the time to look more closely at it. Really, not even close.
But as you pointed out, there is no cascade and no sheet. The styles apparently just apply to the stuff they are near in the code. No twisted logic to unwind, hence no spaghetti.
The potential problem I could see is that changes which would have been easy with a cascade would require lots of changes to copypasta in this approach. Like, "take the spinach out of this ravioli and replace it with mushrooms." Everything is scoped properly and the task is obvious at a glance-- it's just annoying.
Why does copying CSS multiple times (once for each component) not also create spaghetti code?
Many elements share style in a normal webpage. Font, for example. Having to specify the font in every file seems crazily redundant.
And if you separate that out into a separate file that gets included in many places, you lose all the other benefits like "painless maintenance".
Ah, well, things are not that simple.
In a project of any complexity at all, the style of any individual element is typically dependent on a number of things which collectively make up the context of its presentation. E.g, the site theme, the component, and the individual element (at least -- usually there's an app-subsection and components are usually grouped into modules, etc.).
Note that this is inherent to the problem space and is true whether you're specifying styles in code or styles in cascading style sheets or any other way.
CSS provides a basic mechanism for dealing with this -- the cascade (though as I mentioned, IMO it is lacking some necessary features). Styles in code needs an answer as well.
If you were to simply hard-code styles at the element-level (which you can do using either mechanism BTW though its probably easier with style-in-code), you'll have a hard time finding all the places in the code you need to update if you want to make a change. You'll be doing a lot of full code searches, reading code, and trying to put yourself into the mind of the person who wrote the code in the first place.
The "spaghetti" in the metaphor are the lines of dependencies. We have spaghetti code when those lines are disorganized, entangled with irrelevancies, obscured, and otherwise unnecessarily difficult to deal with.
In fact, if you hard-code a style on an element that is dependent on the site theme, app section, component module, and component, you'd be hiding those dependencies, which creates spaghetti code rather than avoids it.
Now, I expect most developers would naturally try to avoid doing something like that. I'm just trying to point out why style-in-code doesn't really help you avoid spaghetti code.
An overview of my tooling and workflow is here: https://github.com/tomhodgins/caffeinated-style-sheets
The big idea being that CSS should be able to apply to _any_ HTML, no matter how it was created before it got to the browser. Many style-related tools integrate tightly into your framework or into one particular workflow but don't give you the flexibility you need to apply any styles to any website unless it happened to be put together with specific tools a specific way, but I don't think that provides enough flexibility.
Of course not: CSS is a bad idea in 2019. In 2004 it solved some of the problems we have React to solve today, but much, much weaker
It took me helping my brother learn how to do web development to shake me out of that mindset. He's not from a traditional webdev background and he got quite far quite fast with React. When he showed me his code, I noticed he was inlining all of his styles in his relatively small React components. I was going to explain why its bad practice to do that, but when you're building small almost atomic components, that approach actually makes a lot of sense, its what the BEM methodology tries to do albeit in a poorer way. CSS-in-JS tools like Styled Components preserve the spirit of this approach and minimise the downsides.
I think CSS-in-JS lends itself quite nicely to atomic design. At my current company, one of the first things we did was build a component library of atoms & molecules that are shared across many applications, keeping our design language very consistent.
We also make heavy use of Styled Components' theming capabilities, so we wrap our React apps with a ThemeProvider and give it an object with theme variables that drive the look and feel of our components. This is super useful when you have to support whitelabeling like we do, but even if you don't, its nice to keep your mystery-meat colors and spacings all in one place similar to how you might with SASS.
One of the gripes a lot of people have with CSS-in-JS is portability, and while that is a drawback, I feel it's an anti-pattern to rely on shared CSS styles to enforce design consistency across many deployables. It's kind of a classic case of developers trying to solve a process issue with technology, which is admirable, but from experience styles go out-of-sync with eachother quite easily and its rare that you can drop a CSS file into another project and have styles just work without having to do rework, so the benefits of sharing CSS rather than writing new styles off a styleguide are marginal at best. Again, this is all my subjective experience, your mileage may vary.
We still have a couple of issues with Styled Components, no technology is perfect and SC is still relatively young, but so far the pros have far outweighed the cons to the point where none of us really feel the itch to go back to SASS or plain CSS. I'm definitively not a magpie developer by any stretch, I'm usually resistant to change for the sake of change, but CSS-in-JS makes a lot of sense when you use it how its intended
I have built websites in a variety of different ways, with a variety of different CSS schemes. I've worked with SASS, LESS, BEM, every major css framework, in both SPA and SSR environments.
I have also built react SPAs with the above variety of CSS schemes, as well as CSS-in-JS libraries like Aphrodite and Styled Components.
I currently build and maintain a medium-to-large web app with a small team, right now ~200 components, 31k lines of js including test files.
Styled Components has been an immensely positive experience for us, and i would not want to use any other way I have mentioned, or has been mentioned in this thread, to manage our styles in our app.
The reason why is because of the simple fact that it allows us to think of our styles just like any other component. We do not need a separate way of managing styles that we need to keep track of, whether a style is used is 100% the same as whether a component is used or not, which makes eliminating dead code, dead styles, easily managed through tooling.
It allows us to define simple, semantically-named components like <FlexGrid/> and <BigButton/>, and allows us to compose these components together to build up styles just like any other react component.
Styles are easily overridden from their parents. We use Ant Design for our UI toolkit, which does not use Styled Components, but any styles we want to override, as well as styles in nested classes, are easily done by wrapping an antd component. All the parent component needs to do is accept a "className" property. This makes interop with other components simple.
Effectively what this means is that after awhile, we get to live in a world where I can add a component into any given part of application, and be very certain its going to look and behave the same way it does in every other part of the application. When I'm building new features I don't want to think about styles, except when adding styles is part of the feature itself. Styled Components is the only way so far I've found that does that sufficently.
Globally-available CSS is great for web pages, but not so much for widget-based GUI web apps, which creates leaky abstractions. Most ways of managing CSS are systems to get around that, or treat it as a feature.
In short, 10/10 would use again, even over other CSS-in-JS libraries like Aphrodite. Note this opinion is scoped purely to react apps. Vue's approach seems appealing as well but I have not used it before, but to be honest I do prefer being able to have everything in JS or JSX, but thats a different discussion.
If you want to use CSS-in-JS, you'll either have to use server-side rendering to inject CSP nonces in your index.htm [0], or set up a complex build system to extract the CSS from your JS so you can serve them as .css files.
Using server-side rendering to inject nonces into your single-page client side rendered webpage is such an ugly hack. I'd prefer the second solution but I have not been able to find a solution like that, nor do I have the time to dive into the webpack rabbit-hole to do so.
[0] https://github.com/cssinjs/jss/blob/master/docs/csp.md
The great thing about React is it is purely JS (or JSX, which is effectively a macro for the underlying JS). Which means it is explicit, and predictable. Perhaps that means there's less sugar, but any sugar and magic comes at a price.
I'm going to have a look at Vue more anyway, out of curiosity, though.
Edit: I note that some of the anger at React has been "Why does it need Redux/MobX if it is so good?". But Vue has Vuex to solve the same problem?
Basic front end code isn't that challenging, but it does take some actual practice (not half-ass practice followed by a million poorly considered short-cuts).
Just about everything else on the frontend is absolutely solid cross browser with 5+ years of thoroughly tested support. People don’t write abstractions to fix weak technology, they do it to fix weak developers.