- Styles are targeted via brittle, untyped, and opaque "magic strings” basically. This means mistakes are more likely to be caught at run time than compile time. Eg, I wouldn't get a compile time error if I did `position: oops` or `class="oops"`.
- Styles are often "far away" from their target which makes mistakes more likely; ie this deeply nested HTML element in one file is coupled to a deeply nested style sheet in another file
- It is easier to perform complex manipulation of styling if it is made up of JS objects. Eg, if I wanted to do math or I wanted one style to be a function of another (eg `marginLeft: PAGE_MARGIN`)
That being said, I’m sure there are some better ways of doing traditional CSS since I last tried it that I’m unaware of...
As far as the performance trade off, I'd love it with styled components did not come with this but, at least for my use case, it is usually worth it
Still experimental of course, but could be very useful if implemented alongside Shadow DOM. Note this isn't 2012's scoped CSS: https://caniuse.com/style-scoped
If we get this the only thing I'll continue to dislike about Web Components would be the global namespace of web components and that Web components HTML attributes can't be rich objects or arrays natively. (I'd love it if web browsers simply implemented JSX, for example, or a syntax that looks like DOM but is actually a function call that can produce DOM. Bonus points if they also implement Markdown or MDX as an HTML element of some kind.)
CSS scoping without a hacky third party framework is long overdue.
Web components largely failed at this point though, the spec needs to be rewritten from scratch to be more pragmatic. People have been using React and Co for more than a decade now, spec writers certainly have enough hindsight as to how people practically program front-end applications.
Web components are a great brand for a collection of mostly awful APIs. Shadow DOM in particular should have just been a CSS property from the start. Glad to see someone starting to recognize this.
Never-mind, read the link. It's just shoveling more crap on top of the existing shadow DOM instead of finally just cutting bait and making a CSS property called `inherit: reset;` like they should have done to begin with.
CSS modules with TypeScript solves the first three items pretty neatly. You write CSS that lives alongside tour component, then import the file into your component and apply the classname to your elements. It compiles to unique classnames that cannot conflict with any others. And with TS, you’ll get a compile error if you use a class that doesn’t exist. The last point is possible either with CSS vars or Sass vars. calc() can handle some pretty complicated math. You can also do plenty of math in Sass.
We’re making the switch at the moment and, after a bit of a learning bump, everyone is flying along with it now. It’s basically inline-styles++ with having all the context right there but not having the edge cases that require breaking out into classes to use media queries etc.
It was a little struggle at first with our previous setup, but I spent a week or so moving everything over to Vite with hot module replacement which has been life changing.
Comparing Tailwind with Web Components might be a bit unfair. It is well known that Web Components have terrible dev ergonomics.
It would be more fair to compare with frameworks that work with scoped styles (such as Svelte or Vue’s single file components). Developing in these is also an excellent productivity boost.
Can anyone give some references on that Web Components have bad dev ergonomics? Is it just that Web Components don't allow passing of complex types so you have to stringify everything?
I see many people have problem with that in the comments here. However I don’t find that to be an issue. Passing properties (as opposed to attributes) allows complex types and many popular frameworks have a handy shorthand for it (e.g. in lit-html you write `<my-component .prop=${[1, 2, 3]}>`).
In my opinion the bad ergonomics is actually when authoring the components (not consuming it). Many of the faults have been excellently pointed out previously[1]. The most glaring the boilerplate you have to write if you want your attributes to reflect a property.
This has an easy fix though, which is that you simply don’t write your web components by hand. You either use a library (like lit-element[2]) or a compiler (like stencil[3]). I’m personally waiting for a less opinionated compiler with a smaller runtime then stencil (preferably no runtime; perhaps that is Svelte with a web component target, I haven’t tried it).
There is also a proposal for a declarative shadow DOM[4], which aims to tackle some of the bad dev experience we have with web components. However I’m personally a little skeptic that it is a good proposal, or that it will fix what most web component devs are concerned about.
It's kind of like bootstrap except it's more focused on the developer building styles instead of having a number of prebuilt styles.
It also is more based on what css can do instead of having it's own abstraction. Most of the class names in Tailwind are very close to their css key+value equivalents. For example if you wanted to write `float: right` in css you'd use the Tailwind class `float-right`.
- Styles are targeted via brittle, untyped, and opaque
'magic strings' basically.
- Styles are often 'far away' from their target which makes mistakes more likely; ie this deeply nested HTML element in one file is coupled to a deeply nested style sheet in another file"
You can get a long way to solving those three issues with good organization, but only if you control your whole project, stick to the plan, and don't have any libraries.
But over the course of a long lived project CSS is a real foot-gun that even well meaning developers will shoot themselves with. It's hard to unweave a tightly woven CSS nest, and once you introduce third party libraries and custom CSS things start to get wild. Who hasn't seen a "custom.css" overriding the "global.css" which was itself just a bandaid to fix an issue with some third party library.
I use a method I called "Contexts and Components". It starts with a reset. 98% of the CSS is inside the component files, and target component classes, eg <div class="product-card">. But of course things can change depending on what page they're on, and those are called contexts. Maybe a product card on the home-page has a border or whatever. That gives you a way to address client requests for things to differ but without making crazy complicated configurable components.
That way things are really shallow, only one level deep unless they are modified by a context, which makes it two levels deep. I find I need way less CSS, no crazy hard to reason about selectors, and it's all very easy to understand. Best of all, it's easy to remove stuff entirely, so you don't end up with overrides over overrides.
Complex manipulation can easily be done with a preprocessor. You can work around the other issues you mention by just, well, learning css instead of fighting against it.
We started using CSS in JS a few years ago because we couldn’t, and still are unable to use CSS variables (some of our customers still require IE11 support and we can’t drop it until 2022).
The main issue I still see with CSS variables is IDE support and static validation. With my CSS written in typescript I know that every variable I’ve imported works statically.
Can someone explain the appeal of CSS-in-JS? I've used scoped styling in .vue components extensively, at a quick glance it seems to offer similar benefits (lives right in your component and is scoped to it), but most importantly it can be extracted to a plain CSS file when building frontend assets.
Is there something extra these React libraries do that prevents them from doing this?
I've worked on and off with React since its inception, and the main reason I would use it is simple ergonomics. If you are working with an MVP or a small widget project, you gain a lot of velocity. You don't need to worry about scoping, naming collisions, class toggles, etc. and as long as you use decently small components, it all fits snuggly in the same file as the component definition.
The price you pay comes in the way of performance and maintainability. Since the line becomes very blurry between styling and markup, it's up to the dev(s) to bring order to potential chaos.
For any bigger project, my go to solution is SCSS modules. It's by far the most versatile solution I've tried if you want to roll your own CSS and not rely on a CSS framework. You don't need to worry about scoping, the bundle process is excellent, you have access to all of your normal SCSS shenanigans and most important it's a solution that makes it dead easy to collect or break down parts into logical units.
I've found it easier to maintain CSS-in-JS since I know exactly what will be affected when I change it. I'm always scared to touch the .css files on large projects.
With my preferred SCSS module setup you get a hybrid solution with the best of both worlds. You can keep a clean stylesheet next to your component and then just:
Where `mainGraphic` is a regular class block in the SCSS. So it's pretty straight forward and the mapping is still fairly tight. At bundle time, the class name is minimized, deduped and a hash is added to it that corresponds to the rule content. The generated standalone CSS file also gets hashed for cache busting purposes. It's pretty neat.
And since it's SCSS you can keep constants, mixins, functions, etc. imported and organized within and between SCSS files, separated from the components.
I'm afraid I don't get it either. To me, the big disadvantage of css-in-js is that the browser doesn't display it neatly.
If I write plain CSS, it's easy to make changes right in the browser and have it react instantly. Or I can make them in the .css file, and webpack (or whatever it is) will automatically redisplay them without having to restart the app.
Perhaps if I had much larger projects I'd see more headaches that drives people to css-in-js. But I manage fairly large things and don't have too much grief with plain css.
This is, what `<link rel="alternate stylesheet" href="contrast.css" title="High contrast">`is for. (Using JS, you can switch between default and alternative stylesheets by setting their "disabled" attribute accordingly.) This mechanism also allows a user to (pre)select a stylesheet in the browser.
Sadly, Chrome doesn't support this standard (it has been around for a while and is in HTML4, HTML Living Standard, CSSOM). But you can work around this by JS, see above.
(Edit: It's for things like this that you still want a menu bar for your browser.)
CSS-in-JS alone doesn't give you many tools for that kind of stuff, but if you use something that integrates more design system-style theming it's pretty easy - have a look at https://chakra-ui.com/ and click on the moon icon in the top corner for instant dark mode. Implementing various themes for high-contrast etc. would just be a case of changing the theme.
Switch the `<link href="">` value to point to a high contrast stylesheet.
Or alternatively, apply a class to the body tag – e.g. `<body class="high-contrast">` – and declare CSS rules accordingly. Specificity should take care of overriding the 'normal' style rules where needed.
I’ve implemented that two ways: having JavaScript pop the alternative attribute off for all but the desired style sheet or simply using a top-level class to modify the relatively few things we were customizing. Back in the day, I used SCSS but CSS Variables have matured to the point where you can do an awful lot that way, too.
I think you should assume malice... but reconcile yourself to the fact that there's not much you can do about it. People engage in petty acts of malice on social media because they can get away with it.
The best you can hope for is to forget about it. It's unsatisfying, but less unsatisfying than trying to get back at them or apply "sour grapes" or whatever. None of that works.
The sooner you put your brain on something else, the sooner you'll forget that somebody was a dick to you and got away with it. It sucks, but it's the least worst alternative. Treat it as noise -- which I think is what the OP was trying to say.
New posts get down modded randomly for whatever reason (iirc it was to disrupt some bot karma farming). Wait a day and the post will almost always be back to to the default (1) + any user mods.
For us the big win is branded sites. We have a white labeled product that is customizable for each client. No code deploys needed to add a new client. Values live in a db table and get pulled in dynamically based on the url subdomain.
Yes, and using CSS Custom Properties/the var() function you can even keep that branding file as small as said table. Could even build it dynamically, if one wanted.
If you want to have a range of applicable values for some CSS property or state-based styling, CSS-in-JS can be a good tool for expressing that as opposed to writing JS that updates some styling declaratively.
For example, I've used it on a personal app to allow adjusting the placement and opacity of controls. I prefer the CSS-in-JS approach because the code is simple to understand, I can reuse the code in multiple areas, and I can pass state to some function to generate the styling. I also imagine that I could also write some spec to support it, but it's not something that I plan on quite yet.
It's not a technique that I would use for ALL styling, but I think for the use-case I mentioned above, it works great.
There are number of techniques that can fit that. State based styling can be achieved with simple class name toggles or CSS animation + the `animationend` event. If you don’t like toggling classes with JS there are number of selectors (including the attribute selector) which you can use instead.
For making code easier to understand you can set a CSS custom property instead of specific style values, and the CSS will be really straight forward.
To be clear - when I need to toggle a basic state with a class or set of classes, that is the strategy I use.
Where that technique fails is when you have hundreds of possible values that can occupy a given state.
If I want to set the rotation or opacity for a control and I want to use a range of values, there is nothing native in CSS to allow me to do that.
You can use SCSS to dynamically generate the CSS class declarations for every possible value, but I would only ever use that solution if I needed the performance boost and that was the only way to get it.
Also I explain on a sibling thread that there is a fundamental difference between setting a custom property (like I do here) and setting a specific style value. While I do see how the latter can be problematic as there are no hints to the changed style in the CSS file, the former does not have that issue, particularly if you name the property with a hint to the dynamic nature if it.
If you want to have a range of applicable values for some CSS property or state-based styling, CSS-in-JS can be a good tool for expressing that as opposed to writing JS that updates some styling declaratively
I think there is a fundamental difference in setting style properties in JS and setting CSS custom properties (even though CSS custom property is a style property). The main difference is that it is clear from the CSS that this property is dynamic and can be expected to change. If you overwrite a style attribute (e.g. `element.style.transform = "rotate(50deg)"`) this is less clear.
So in honestly I don’t see how setting a CSS custom property in JavaScript as lacking in expressing the intent.
The main use case highlighted in the article is React and that is the use case that I am speaking to.
With React, you don't modify the DOM directly, so the use case you have laid out is not applicable.
With that in mind, you are still free to use the CSS custom property with React, but if you want to have multiple transformations across multiple parts of an application, it's a lot simpler to use CSS-in-JS to generate styling based on state.
The use case you have brought up should work well with vanilla js/jquery; however, the context of the discussion is rooted in front-end libraries and the popularity of CSS-in-JS, so I am not sure how custom properties are relevant.
If you have a lot of dynamic styles that respond to application state, then even with vanilla CSS you are often writing JS to manage class declarations to get the right CSS combinations. With styled-components, instead of adding/removing/combining class names, you can write javascript inside your declarations that use the state variables.
For me, writing javascript that directly sets css properties based on state variables is a more powerful and clearer approach to managing dynamic styles than manually managing class names.
Further, when combined with typescript, you can type a theme object in the styled-components theme provider and get auto-complete in your editor on your style tokens like colors, spacing values, timing in ms, etc.
So it has many benefits beyond scoping styles to a component.
I’ve had great luck achieving that with CSS custom properties. I assign a custom property to a style rule and then change that property with JavaScript when needed.
I also find much state has a nice selector (e.g. :hover, :checked, :invalid, :empty, :focus-inside, etc.) or media queries `@media (prefers-color-scheme: dark)` which I can change the custom property values inside. So it is really an exception when I manually need to change the value of custom properties with JavaScript.
> For me, writing javascript that directly sets css properties based on state variables is a more powerful and clearer approach to managing dynamic styles than manually managing class names.
I'd argue there's a lot more flexibility available if you choose to use classes.
Sure, it's more complicated and involves more work; but to say it's less powerful just isn't true.
> there's a lot more flexibility available if you choose to use classes
That is simply not true. Apart from what was described in the post above, in JSS frameworks such as styled-components, you usually have ways to hook directly into css parser, allowing you to implement custom expansions, replacements or basically whatever logic you want. This is not possible unless you write your own language and transform it to css.
However, when used correctly you can create a system that will allow you maintain and apply your presentation layer in an efficient, extensible, consistent and reusable way.
Lack of knowledge isn't an excuse for believing otherwise.
--
Edit: I'm actually shocked by how much bad feeling there is for standard front-end technology.
> you can create a system that will allow you maintain and apply your presentation layer in an efficient, extensible, consistent and reusable way.
If that is your intention, typescript is a better tool for the job: you get type safety, ide autocomplete, tests (have you ever written a test for css?). You are right, being a domain specific solution is a benefit, but that has nothing to do with how good of a system you can make with it. I'm sure it's possible to write a system in typescript that would be as good as what you describe, but it will be more flexible at expense of being slower.
CSS and Javascript aren't concerns, they're technologies, and separation of technologies isn't a software engineering principle. "Concern" is pretty undefined in general. If anything, they're all part of the "view" concern. It's the same reason why JSX doesn't violate separation of "concerns."
Moving goalposts is not a concern either.
CSS and Javascript are concerns, becaus HTML is of content/structure, CSS is for styling and JS is for behaviour. Of course somewhere along the road devs thought that HTML and CSS are to primitive to spend any time learning them properly, because of that they later found them to bee too complex and we ended up in the mess we are right now, when we try to hide the lack of understanding under multiple wraps of abstraction.
I don't think it's that clear cut, you can define all sorts of behavior with both HTML and CSS, and there's no semantic meaning in `<div>`, which itself changes page style due to its layout properties. I don't know what goalposts are being moved, React/css-in-js have never violated separation of concerns. After all, css-in-js produces CSS, and React produces HTML. Separation of technologies isn't a principle, but DSLs are a well established pattern.
The web has never lived up to that ideal. Sometimes you need to add a wrapper div with no semantics to make your layout work. Sometimes you need some Javascript to do a special layout CSS doesn't support or work around some other limitation. I've never seen a project that actually had meaningful "separation of concerns" based on technology, whereas almost every componentized project has at least decent separation of concerns along the component axis -- where you can drop a component into a design without thinking about it's internals at all.
I don't see CSS-in-JS as a rejection of separation of concerns. In fact, one of the big advantages of CSS-in-JS is that it lets you decide how best to separate your concerns.
Using hand-tuned CSS will undoubtedly be the most performant option, but it leaves you with very difficult problems at the boundary of your styling and content/structure concerns. If you have even a sliver of dynamic content in your website, it will quickly become near-impossible to verify that your content and styles work together as expected, or even to verify that your class names match between your CSS and HTML.
On the other hand, if you use CSS-in-JS, what you lose in performance you gain in compatibility guarantees between your concerns, regardless of how you prefer to separate. Are you putting your styles in the same files as your layout components to fully separate one feature from another? Great, you can unit test those components and be reassured that the elements are styled as expected. Are you isolating your styles to only a certain subset of components that deal directly with styling concerns? Also great—if you're using TypeScript, you can guarantee correct use of those styles at build time.
For a large enough team, those guarantees really pay off. If you have lots of customers using 2G/3G networks and want to hand-roll your CSS, I commend you! For most products, I think there's a better way to make that tradeoff and your users won't mind a slightly slower experience that has fewer bugs.
If you want to replace all the styling in your project, because you've had a rebrand; I would argue that CSS in JS makes your life more difficult.
If you want to share styling between your app and your website; I would also state that this process is made more difficult.
If you want to create, implement and maintain an atomic design system to build in consistency and reuse .. again, more complicated that it might have been.
To add to that, this article suggests that there's a performance deficit.
We're migrating to styled-components at my current company. It's nice for abstracting components -- either into shared libraries or separate micro-clients that are composed together at runtime.
In those scenarios, there are a few benefits: (a) no worries about accidentally trampling on someone else's styles, or styles from elsewhere overriding your styles; (b) build configuration is simpler; and (c) no worries about how CSS/SCSS is referenced/loaded - all references are handled in plain JS with no special loaders or anything.
I wouldn't use it everywhere (I've used other approaches that have worked just fine), but for some scenarios it makes sense.
When using server-side rendered pages, there's no performance loss on the client-side, maybe a little more processing server-side, not sure if significant
Some of the React libraries do support CSS extraction to plain CSS files.
styled-components does not, and I'm not sure exactly why. It may be related to that they support runtime variables inline as React props and/or that they didn't want to complicate the build pipeline more than they already complicate it. (Many of the libraries like Vue's have necessarily tighter coupling with webpack or whatever other packer they use to get the extraction automated.)
For highly dynamic styles it allows me to avoid all the logic around coming up with class names and applying them. Think of it less like traditional CSS and more like a super version of inline styles.
I think there's a conflation that confuses this: We have CSS in SPA components vs CSS, and inline CSS in HTML. In the latter, you may prefer inline to prevent flipping between files, and creating reusable data structures that are used once. In the former, you may have the same, or additional reasons like programmatically changing styles.
Css-in-js helps minimize context switching for logic related styling, believe this is one of the main advantages from a developers perspective. It also allows javascript developers to colocate their CSS where they want, separate file, inline, same file, etc. This is more flexible than a .vue file in that sense.
An underlying appeal of React is it's just Javascript (yes even JSX templates). CSS-in-JS gives you the same flexibility and control over CSS from Javascript. No need to learn SASS, Less etc. It replaces the functionality those utilities with just Javascript. No setup required.
For anyone capable of using React, there's no barrier to 'learning' sass (you can be productive with it in about 30 seconds). Admittedly there might be some additional work around configuring compilation to work with the rest of your build and dev processes, etc. But sass in it's most basic usage (nested selectors) is really what CSS should have been.
We actually do this at my company. Our user base is mostly security focused and browses with javascript disabled so we had to find another way to make reading a simple text with some pictures thrown in terribly slow for them. We like it so much that we are currently developing a server runtime for it called node.css. We are also working on a meta package manager based on this runtime so we can manage our dependencies on different package managers more easily.
Nobody mentioned this, but for me big benefit is that you can remove everything related to css from webpack, and no dependency on ruby/dart/whatever else. Oh, also autoprefixer out of the box.
Great effort and I have no dispute with the methodology. The conclusion, however, is naïve. Specifically this part:
"Great developer experience shouldn’t come at the expense of the user experience."
Great developer experience can conceivably deliver better user experience. A more capable, responsive and lower defect application that load 10% slower may be a net improvement.
I'm not arguing that CSS-in-JS actually delivers that. Only that load times aren't the only variable in the "user experience" equation.
I very much agree that load time is not the only metric that should be measured. Unfortunately, it's one of the easiest to measure. It's also one which does not sacrifice any other UX metric like low completion time leading to less satisfaction sort of corruptible metrics.
Although, in my experience, usage of react is not indicative of a more capable, responsive, or lower defect application. Quite the opposite (for me) actually. React is a good (but not absolutely reliable) indicator of slow, unresponsive (in terms of response time, not resolution scaling, buggy, and frustrating UX.
From the code examples of the suggested library, it looks like a pretty simple drop in replacement for many (if not all) cases. 10% for free would be a slam dunk.
As someone working predominantly on React sites for the last 4 years or so I absolutely agree. Of course you can write quick, responsive and solid sites with React but it’s not the automatic process some would like you to believe, you still have to try and often the effort required is not trivial. The problem I often find is that optimising React sites needs a bunch of knowledge and skills which are only tangentially and most related to those which you’d use to optimise a more traditional site. This is related to the topic of the OP i think; knowing how to write good css is a skill which css-in-js tries to pretend doesn’t matter but which absolutely does - things like Styled Components effectively enforce certain good practices but don’t remove the need to understand whats going on under the hood in all but the most basic of situations.
It's funny how we are going from one orthodoxy to another, from "separate logic from presentation at all cost" to "inline all css directly in your HTML tags".
It reminds me the era when devs were chastised for using tables for layout, and using floats was deemed the right way to do things, when both techniques were essentially just hacks with both their strengths and weaknesses (overflow:hidden anyone?), but somehow the entire dev community was gazlit into believing that "tables" for layout were bad. Tables weren't bad, CSS wasn't just good enough, otherwise Flexbox or Grid would not be needed.
Flexbox considerably simplified CSS layout. The people who never had to use a single float attribute in their style declaration cannot fathom that.
CSS, the way it was designed, has been terrible for a long time and a thorn in the side of generations of web developers, but nobody want to acknowledge that. IF there is one thing the web failed at, it's absolutely CSS, from its syntax to the way it works in conjunction with HTML And Javascript.
The reason tables for layout were so bad was that the table as a whole couldn't be rendered (laid out) properly until every cell was fully rendered first, including images with unspecified width/height attributes as well as dynamic cell dimensions based on free-flowing text, etc. Floating div tags still cause redraws for containers with content requiring dimensions to be determined at runtime, but at least something would display. It was also easier to see which divs were causing redraws because their dimensions were not fixed, and thus developers could focus on those specific regions to try and add fixed dimensions.
edit: My comment sounds a bit angry, but it's not directed at you personally, so keep it in mind ;)
> The reason tables for layout were so bad was that the table as a whole couldn't be rendered (laid out) properly until every cell was fully rendered first, including images with unspecified width/height attributes as well as dynamic cell dimensions based on free-flowing text, etc [...]
That was purely a limitation of the CSS rendering engines, it had absolutely nothing do to with table layout themselves, from a developer perspective. There is no reason this problem cannot/couldn't be worked out by CSS rendering engine developers. I get what you are saying, but it wasn't a good enough reason to dismiss tables entirely (and that wasn't the biggest reason used back then when "a list apart" writers decided that tables were cancer).
Floats were so good yet developers had to resort to CSS frameworks and grid frameworks for years in order to make working with CSS bearable? No, float positioning was horrible, un-intuitive and just a hack. Again, the culprit was CSS itself (and by extension the rendering engines), not the developer using tables.
The irony is that all these CSS frameworks were essentially tables re-implemented on top of "floating divs".
A good measure of whether a web spec is good or not, or pragmatic enough or not is how much effort developers go through in order not to use that spec directly. Generally, if using a framework on top of the spec to make that spec somehow useful is what most developers do, it means that the spec needs to be revised and improved in order to fulfil the needs of the developer, not the other way around. Obviously that doesn't apply to low level protocols like WebRTC and co, but CSS isn't a low level protocol, it was supposed to make web presentation easy, and it failed at it for decades. That's all I'm saying.
Just thank god we now have at the very least Flexbox and Grid. Which makes bootstrap and co completely redundant even for devs allergic to design.
I recently made a simple layout with flexbox with about 60 lines of css (header, content area with two sidebars and footer) that would've taken either 500 lines of css or had to pull in whole css frameworks to do it. Flexbox is pretty close to what we are used to on desktop applications.
Using almost no absolute pixel sizes and none of the usual suspects (clearfix, floats, position: absolute, z-index: 9999 ...none of that crap).
This is an apples to oranges comparison -- a run-time compiled stylesheet vs. a statically-generated stylesheet. Styled Components has options for statically-generating their stylesheets (https://styled-components.com/docs/advanced#server-side-rend...), so why wouldn't you compare those?
Might not be a fair comparison, but there are people who are looking at changing up how their css is written so it makes sense to be aware of the differences in performance.
Definitely should be aware, and I would highly recommend static files over large JS apps. The options are there to have both now with frameworks like Gatsby and Next.
You linked to server side rendering, not static extraction of styles, did you mean something else?
The point of static extraction (something the current wave of new CSS-in-JS libraries seem to be focusing on), is to generate all the style sheets at build time and serve them as regular CSS files — so that your styles don’t inflate your JS bundles (a problem most older CSS-in-JS libraries have).
SSR would extract all the styles out for the styled components, but I guess now it would have an advantage as all the html/js would be as well.
My point is, the comparison seems more “js runtime stylesheets” vs “regular static stylesheets.” Styled Components, or CSS-in-JS, isn’t really the main focus here. There are options to get the static stylesheets generated, and I predict most CSS-in-JS frameworks will eventually provide the tools to do so.
With conventional CSS-in-JS solutions like emotion and styled-components, SSR with these libraries still extracts the stylesheets at run-time, so it's not static extraction -- where the extraction is done at build-time. And your style definitions still live in your code bundles -- inflating the size.
Both emotion and styled-components have dabbled in supporting static (build-time) extraction, but it's actually a hard problem to solve when you have such flexible APIs. The libraries that have cropped up to support this notion of near-zero runtime CSS-in-JS (Linaria, Astroturf, vanilla-extract, and more) do so by providing tighter constraints surrounding what you can and can't do.
A 4 year experienced react dev here. I have had decent time working with different styling
I'll try to answer few common things for everyone's context
Why even use CSS in JS?
- SPA bundling usually loads all CSS at once and all styles collide. You need to be super good at naming stuff/or load CSS based on module. So your CSS will be conflicting, so scoping is helpful here.
- Not having to jump from your component file to CSS file. Save some context switching or few strokes.
CSS modules solves all of these problems (except the separate file), and also lets you write vanilla CSS, and not have to hack around the limitations of css-in-js. Dynamic styles are easy with React's `css` prop, or simply passing in an additional class name.
In the end, I generally prefer to use tailwind + emotion. My goals usually is to save time and make system more consistent rather than perf gains, which isn't that much on new systems.
Looks like a well designed library (and it is only 40 lines long - but then the original isn't much bigger). But it's hard for me to imagine code where this is a bottleneck.
It depends a lot on the context if that context is React. CSS in JS in retrospect looks like a shim for react developers who couldnt rewrite their code to single-file components like in Vue and later Svelte. You dont have to be a genius to know how to name and structure dom elements, though being good at it lets you reuse css and reduce overall app size better than any bundler ever will - but its just easier to install Tailwind.
Whenever you talk to somebody about how ridiculous it is to need a preprocessor to do basic sane things in css, you hear about how “css isn’t designed for that, it’s better this way. Use a preprocessor!”. Preprocessors are a workaround, not “the way it should be.” There’s no good reason why a @media query can’t take a variable for a min-size value, it just makes things error prone. Yet, the css spec is so proud of itself it has declared that there will never be a css 4
I'm not a fan of web frameworks such as React and CSS in JS, but to be fair, you should not stare blindly on first-time-load times! Imagine if you would include download and install time when you measured native app performance... You should also take into account repeat use performance! While most "users" will just load the app once and leave, those who actually use the app will spend hours clicking around and doing stuff, and that's where aka "single page app" have an advantage over full reloads. Measure things like click latency and re-render times!
It gives you in my opinion a nicer style syntax (flat style props on the component) while avoiding the downsides of CSS-in-JS by extracting everything but the most dynamic parts to pure CSS.
The optimizing compiler part was a large investment to get right, especially with theme and media query support. But the main claim to fame is that it also works on React Native, and optimizes there as well, so you get for the first time a really performant way to style native and web apps at once.
I noticed this a while ago. Some people with the ability to downvote, downvote some comments for no reason, other than hating the comment somehow. They try to release their hate through the downvote, which is funny actually.
We have a "write tachyons/tailwinds CSS-in-TypeScript" project [1] that can sit on top of any CSS-in-JS runtime (emotion and fela are both supported).
I'm hoping to eventually find one of these build-time CSS-in-JS frameworks that is smart enough to partially eval ~80% of our `<div css={Css.m4.black.$}>` expressions to be zero runtime.
And, if/when this happens, do this as a seamless upgrade to our existing codebases, i.e. without any lines of `css={Css.m4.black.$}` in our app need to change.
Basically we're using our Truss DSL both for atomic/utility class names today + a decoupling layer to switch CSS-in-JS libs in the future if/when needed.
I think Linaria and https://github.com/twstyled/twstyled (based on/forked from Linaria) are the closest to doing this eval during compilation, but haven't had to dig in so far (runtime emotion has been fast enough for us so far).
I think an important caveat here is that in a serverside-rendered context, linaria’s 70kb of CSS would be a bigger issue than styled-component’s additional JS. The page can’t render until it has downloaded the CSS.
Granted, many react apps aren’t serverside-rendered, so these numbers are still useful and interesting. But I would say that if performance is a priority, moving to an SSR solution (or away from React altogether) would have a way bigger impact on performance.
I mean, I can appreciate some basic stuff like this but how about measuring rendering performance on low end devices? Like having large, medium, and small css files vs having the same thing BUT moving state changing things to js so that some specific styles are applied inline.
Somewhat superficial content but might spawn a few interesting discussions.
Big surprise that using CSS the original way it was supposed to be used... is the most performant. CSS-in-JS has always been a sort of "hack" for me. Sure it's a great DX, but it's really just an abuse of JavaScript to have CSS capabilities "just because we can".
In theory there's nothing CSS can do that JS can't, as long as the browsers provide the equivalent API for it. Any other performance difference will go away once they devote some resources to optimizing it.
The real question is whether we want styling/theming to be in it's own domain specific language. From an ergonomics standpoint, CSS is such a bad language we would rather write JS instead. But the downside of not having it in a more restricted language is that it's much harder to build tooling for it. For example, you won't be able to open up any webpage and know you can inspect and change the style of things. Instead you need to know the specific JS class for that component or ThemeProvider and modify that instead. Every ui framework is going to do things slightly differently which will be a huge blow to user customizability.
> Don’t use runtime CSS-in-JS if you care about the load performance of your site. Simply less JS = Faster Site. There isn’t much we can do about it. But if you want to see some numbers, continue reading.
- Styles are global
- Styles are targeted via brittle, untyped, and opaque "magic strings” basically. This means mistakes are more likely to be caught at run time than compile time. Eg, I wouldn't get a compile time error if I did `position: oops` or `class="oops"`.
- Styles are often "far away" from their target which makes mistakes more likely; ie this deeply nested HTML element in one file is coupled to a deeply nested style sheet in another file
- It is easier to perform complex manipulation of styling if it is made up of JS objects. Eg, if I wanted to do math or I wanted one style to be a function of another (eg `marginLeft: PAGE_MARGIN`)
That being said, I’m sure there are some better ways of doing traditional CSS since I last tried it that I’m unaware of...
As far as the performance trade off, I'd love it with styled components did not come with this but, at least for my use case, it is usually worth it