Re: “How does writing CSS in JS make it any more maintainable?”
gist.github.com
gist.github.com
You make it sound like a bad thing.
The web is a lot of things for a lot of different use cases. There may be a use case for stuffing all JS into javascript, and base64 encoding all images inline, and maybe even for cramming web fonts into a page via JS, if that's possible. But that's not "the modern web." That's just hype.
The modern web is the right tools and strategies for the job.
Many of my sites are focused to low-education, low-ability, and marginalized people. That means accessibility, semantic coding, standards compliance, and clarity are paramount.
The "model breaks down" only when you're not organized, or fail to document properly.
Your sites may be games or whiz-bang SPA's, and JS is good at those things, and maybe shoveling everything into JS works for you.
But to say that "the only way" to do anything on the web is the height of hubris, and closed-mindedness. How will you know when the next great thing comes along, if you've already committed yourself to an "only way?"
It's not the only way to do web development. But it's the only way to structure UI for an application. It's the pattern native developers have settled upon and used for decades. That's why it's been so frustrating for me waiting to see this paradigm come to web development. It's what iOS/Android/MacOS developers have enjoyed for years.
The tooling is finally mature now, and it's actually fun to develop for the web these days. But before the modern React/Babel/Webpack development environment, it was really tough to build large scale maintainable SPAs without massive expertise. There were things like GWT, Closure, Backbone, etc. But the sort of "batteries included" UI frameworks and IDEs that developers enjoyed in native development was nonexistent on the web until recently.
No, it's not. Want consistency in all your text boxes/links/buttons? Are you going to copy/paste or inherit from a base button component or define the general common styles in one place and have the browser automatically apply them with 0 thought.
Need a button to be different - then do inline styles or more specific selector(incl. CSS in JS) or use !important.
As parent poster said, definitively stating there is only one true™ way to do something is the height of hubris.
> That's why it's been so frustrating for me waiting to see this paradigm come to web development
Inline styles were the norm for quite a long period of time...
import Button from '@material-ui/core/Button';
export MyComponent = ({actions}) => (
<Button
variant="outlined"
color="primary"
onClick={actions.save}
>
Save
</Button>
);
[1] https://material-ui.com/demos/buttons/Those are nice! But they don't require that it be easy to swap out one global CSS for a completely different one. Which is what is accused of "breaking down" in the post you replied to.
Know your tools.
Not particularly. You can use pretty much any modern framework, they are all using a component based architecture for the most part. Vue, React, Polymer, even native web components are usable now. Here's an example of how Ember does it:
https://github.com/ebryn/ember-component-css
It's just about breaking down your pages and views into small components which can be reused and maintained separately. Instead of having one giant stylesheet with a deep inheritance of cascading classes, you just have a a bunch of components that are imported and namespaced by the compiler. That extra layer of abstraction gives you the ability to organize your project in a way that isn't beholden to the specific quirks of CSS, and removes the mental burden of things like SMACSS from the developer.
If you want all stylesheets living under src/stylesheets or if you would rather have them each live inside a component folder.
The latter allows for better portability of components but you generally will need a build system.
In your $complex_app you probably have JS generating most (if not all) of the HTML seen on the page. CIJ just says that the JS should generate the styles as well so that each component in your page is self-contained.
Centralized/shared CSS can work great in a content focused site. It works horribly in an application where component behaviors might share common terms, and potentially clash with natural naming for styles or nested definitions in particular. You only have to look at how most developers create hacky patches on top of Bootstrap, as opposed to using the source the way it was meant to be.
CIJ is a much more sane approach to application components. Look at the material-ui component library for a great example (which uses react-jss). Being able to reuse configuration from a swappable theme has worked great in an application that may have differing configurations based on deployment.
Personally, I prefer to use Sass, logically separated into files - one with variables, another with global and general styles that are inherited, and then one for all buttons, one for all forms, one for all modals etc.
I find this middle ground works well, keeps styles consistent, is DRY 'enough', and is easily maintainable.
With CSS in JS, I just have to deepmerge some objects (from JSON), and poof, it all just works. Without this it's either a rube-goldberg contraption that builds from styling on demand either from sass, or monkey patching styling.
I've done large projects with JSS and CSS/SCSS. I'll take CSS in JS (JSS). Yes, the syntax is slightly more annoying, having to wrap selectors as strings, and wrap values as strings (mostly). Though, I can pass in values from both a theme (injected with the options above) as well as handle manipulation of values at the component (ex: padding: theme.spacing.unit * 2). It's got all of the advantages of SCSS and more. The difference is mostly syntax for keys. paddingLeft vs padding-left.
https://developers.google.com/web/fundamentals/web-component...
https://news.ycombinator.com/item?id=14804175
Our product, Elevate Web Builder, has been using component-based visual controls with no CSS since 2014. It's modeled on the traditional way of doing components/controls in Delphi's VCL and .NET's WinForms, with a splash of WPF in terms of how control interfaces work.
It's a complicated pipeline but it's pretty unbeatable when it comes to writing DRY, reusable, maintainable code. Everything is namespaced automatically and you can go from writing unweildly BEM class names to short, succinct and descriptive classes.
I think this may be the best way, yes. It's not the only way but it feels like a well formed statement otherwise.
Is this what ghci-hs and the like might be giving us? Hard to learn, hard to apply but composition is a given and typing and inheritance come along to help?
Personally, I love react-jss as it's integrated with the material-ui library. Theme configuration flows in easily for reusable options, while behaviors are completely isolated. IMHO it's a far more natural experience overall.
I will say that having to mix selectors and strings is slightly harder than writing direct CSS, and using the camelCaseOption over css-case-option takes getting used to. It's been so worth the tradeoff in the couple applications I've used this approach with so far. Managing and injecting separate style paths, inheritance from a configuration sheet, themes, etc was always more difficult with scss/less.
The SASS is still sort of a parallel codebase in a sense, and doing things like defining constants in SASS that also need to be consumed by the Javascript isn't easy like it would be in pure Javascript.
No, that’s the whole point of modules, use whatever class names you want, when compiled the actual class name has a small randomly generated string appended to it to prevent clashes with styles for other components.
> I will say that having to mix selectors and strings is slightly harder than writing direct CSS
I just use interpolation, e.g.: className={‘btn-sm ${styles.whateverClass}’}
Or you want to reuse Configuration values across A and B components, but C and D components are a different variant. All of which are configured differently on different deployments (application deployed to different clients with different themes).
Easy, have the build process select a different variables file to be imported by the entry point, with different colour variables per deployment. You ask the question in an accusatory manner as if you think this is difficult.
> Or you want to reuse Configuration values across A and B components, but C and D components are a different variant. All of which are configured differently on different deployments (application deployed to different clients with different themes).
What exactly do you think is stopping you from programmatically selecting styles in this situation? I’m not getting where you think the difficulty is arising.
a) setup the entire build toolchain for SCSS in the application
b) deepmerge some JSON, and have the app use that.
I've had to do it both ways... B is far easier to manage.Indeed, I’d be willing to put in the extra work to keep it if I did require such functionality - probably this is as simple as loading the scss variables from json, so I doubt there’s a significant workload involved.
[1] https://material-ui.com/ [2] https://www.npmjs.com/package/react-jss
I don't see any reason to do it any other way, and it scales just fine for the systems we build.
1) Parse CSS
2) Hash styles object
3) Serizlize and auto-prefix CSS back (or just write to StyleSheets API)
That is actually a nightmare for performance. You can say that you can export static styles via babel and everything will be fast again (since 90% of your styles are static), but styled-components, glamorous, emotion and friends all ditched static styles exporting feature.
On the other side we thought that composing styles is a good thing, but it turns out to a complete mess where you have 100s of style overrides across the code instead of building a small component with appropriate API.
On the last side i personally came from mobile world. Most of mobile (native) devs tried to build their own "css" or manage styles in some "special" way that it used to be (constants in some static class). It turns out it adds almost zero profits and too much of maintenance. They are not helping you to simplify things if you wish to change something "everywhere" beside very simple things (dividers, borders, backgrounds, tint color) and everything is just became useless. Building real components is much much better.
Well, considering all this we have only one (!) CSS in JS library that satisfy this requirement: https://github.com/jsxstyle/jsxstyle
It is fast, performant and completely static if it possible but it is not "fancy" in frontend community. As usual in frontend there are not much sense everywhere and popular libraries are usually a complete crap if you really value your users.
I think it depends on your requirements, we have a messaging app and i need to switch chats in < 30ms without caching of pages. Otherwise page will be junky for non-chrome browsers.
`This plugin adds support for server-side rendering, minification of styles, and a nicer debugging experience.`
It is really super fast since all your layout is compiled to a simple divs with a classNames whenever possible (almost always) and it became zero-runtime styling and this is awesome, this is the only way to build fast app - do nothing in your app if you can.
Why? Why in the world would you ever willingly want to go back to that? Has the JavaScript community collectively lost it's mind? Or has all that kool-aid gone to its head and everyone is under the impression that they can do no wrong? What happened to all that talk and bluster that Java and JavaScript are different?
Even .Net and Java have moved away from that convention with XAML and JavaFX.
Those who don't remember the past are condemned to repeat it. My only hope is that the JavaScript community comes to it's senses before it is too late and they take down a good language and platform because of their inability to look outside the bubble.
When developing a website with mostly static or cms type content, it's fine to establish a common layout structure that targets css output like sass, less, pre/postcss etc.
When developing an application with components, it's generally best for component styling to stay closer to the component. CIJ is simply an option that works very well with all the advantages of per-component styling. But over separate .scss files has the added advantage of easily injected runtime/configuration values. It's much harder to generate different global values for $primaryColor and related in scss for different deployment targets. More so if you want to swap out themes, or certain options via application configuration in the application.
Much harder? The tools are often one and the same. I use webpack to bundle my JS and CSS. Configuring a different SCSS entry point based on deployment target isn't strategically different from changing a JS entry point in webpack. If I'm using SCSS imports in my JS entry point (and configured the webpack loaders to do their magic for me), it's exactly the same effort. I've even got one project that injects its theming dynamically with a runtime import(…) and webpack just does its usual thing when bundling that dynamic import.
Correct me if I am wrong, but isn't this the whole point of Cascading Style Sheets?
> It's much harder to generate different global values for $primaryColor and related in scss for different deployment targets. More so if you want to swap out themes, or certain options via application configuration in the application.
Isn't this exact problem solved by custom css properties/css variables? Why recreate CSS in JavaScript with all of the compile-time and run-time overhead when you can write a small function to manipulate css variables?
button {...}
Now you have a component where there's a variation on the button... .foo button {...}
Now you want all buttons to have that variation... button {...new...}
Now you change button defaults... button {...new...}
Oh crap, `.foo button` is broken.Are you suggesting that I setup a complicated system to do SCSS generation across the source of the entire application at each one of those layers? (including runtime, on-demand). Sending JSON, and merging JSON is FAR easier.
On a related note, that gave me the benefit of consistent styling that was more or less taken care of, with all platform-specific features like accessibility and keyboard shortcuts available.
I've spent over a decade fighting with CSS. Sass was a welcome upgrade. CSS-in-JS is a welcome next step.
Easily done in Sass env but requires tooling/work: - Automatically shipping the smallest styles per page/component. - Automatic autoprefixing - Hashed selectors (avoidance of conflicts) - Tree-shaking (no unused styles)
Should your backend authentication code live in the same file as your billing logic? Probably not. Separate concerns.
But when the concern is "a sign up component's look and feel", I see nothing wrong (anymore!) with lumping it together. In fact, I prefer it. Just my two cents.
The cycle seems to be to separate things clearly, then mix them back again, then separate them out again. I’ll happily skip the mixing part of this cycle.
However, that said I don’t want to give the impression that I’m being proscriptive here, other developers are perfectly free to have their own preferences just as I have mine.
// RenderComponent.js
export default props => (
<div class="foo">
<button ...>...</button>
</div>
)
// RenderComponent.scss
.foo {
button {
...
}
}
It looks to me like your stylesheet pretty much has the exact same structure as the component/template does. When you change one, by necessity, you change the other. Don't seem to be separate concerns to me. Only separate technologies.Now, lets say you want your component's styling to adjust based on properties passed into the component... It's going to be easier, more consistent and less of a problem to make these kinds of variants with CSS in JS techniques. You can still inherent styling values directly or through theme injection.
I've used CSS Modules and enjoyed them a little bit, but they aren't as "automatic" as many CSS-in-JS solutions, for example:
1. You still need to come up with class names, they're just not the ones ultimately used in the output because of the mangling. But you are technically still coming up with them in your source code, which is a little bit of effort.
2. You still need to manually map the local/source names from the module to the DOM elements that they apply to. Basically you are keeping multiple files in sync: decide on the local/source names in the SASS files, then import those in some other file, and remember to apply all the same names in the right places. The output names will be different, again, but you still need to do this work to keep the local/source names in sync.
For (1), with some CSS-in-JS approaches, you choose only a component name and the matching class name is decided automatically, so there aren't multiple files to keep in sync. With other CSS-in-JS approaches you don't even need to come up with the component names either, you just get a `css={...}` attribute and can skip any naming work altogether.
For (2), with approaches like styled-components, the class names are applied to the right DOM elements automatically because they are fundamentally tied together – so you aren't writing `class={...}` everywhere, which is still necessary with CSS Modules.
Not to say that SASS Modules are bad, but those are some reasons one might prefer other solutions.
I have to say though that this doesn’t seem like much of an advantage - it boils down to not having to create class names and use className={...}. The other possible advantage is not having any .css/.scss files, which to me is actually a disadvantage- I quite like the separation of concerns concept, having html and js mixed together in jsx already irks me, adding styles as well is just too much!
Also, with css in js I believe that pseudo elements and animations are an issue, whereas there is no problem with these with scss modules. They both seem like valid options, but for me modules wins it.
Here you might be remembering a particular, older technique known as "inline styles." This is probably the oldest CSS-in-JS technique, and has greatly fallen out of favor.
Modern CSS-in-JS doesn't use that method anymore, and can do everything that normal CSS can do (in part because it really is just generating real CSS). So pseudo elements, media queries, animations etc. are no problem. :)
Is there a more general name for the argument in defense of a technological movement on the grounds that it prevents users of said tool from making a certain mistake, and that mistake is so disastrous that we see it necessary to implement a drastic change with wide-ranging demands on an entire class of users or eliminates them entirely from the user base?
I see this kind of argument prop up all the time in these types of discussions and something about it just fundamentally irks me, but I can't put my finger on it. It's kind of like Google's AMP, where instead of making incremental changes to the technologies in question, we'd rather draw an arbitrary line between "good" and "bad" uses of that technology and create a fork or subset of that tech where only the "good" uses are allowed.
For a less controversial but equally relevant example, see Crockford's "Javascript: the Good Parts," which irked me at the time as well for the same reasons, even though it became universally accepted (although not-so-universally applied).
I'm trying to come up with an example from my favorite language (Ruby) and I can't. Ruby's approach seems to be to discourage "bad" use cases by making them ugly (ex. instance_variable_get) rather than preventing them outright.
For example, I'll usually have a constants.scss file that I @import in other files, which for example will have a $max-modal-width: 600px;
I have run across use cases where I want to read that value from JS, but I could never figure out how to do that and resorted to duplicating the constant's value in my code. CSS-in-JS would make this trivial.
With SCSS/Less, it's actually painful to try and inject these values in to the build, and more prone to error. In your example, say deployment A has a $max-modal-width of 600px, B is 550px. Or colors are different, fonts, other styling.
var style = getComputedStyle(document.body);
console.log(style.getPropertyValue('--color-font-general'));
:root { --color-font-general: #336699; }
As a bonus point, you can also change the values of CSS Variables and layout will update automatically. Take a closer look at styles of YouTube.There is more coming in project Houdini. https://developers.google.com/web/updates/2016/05/houdini#th...
Java was a good example of this. Instead of fixing core language issues, people used increasingly sophisticated IDEs and put more and more things into XML. Instead of adding essential functionality to the standard library, everyone said "just download this great third-party JAR". At the time Java community said the workarounds were good enough. Right now it's obvious that they were completely wrong, the pileup of complex tools wasn't sustainable and that the language itself needed improvements.
const styles = theme => ({
myComponent: {
...theme.typography.body1
},
});The recommendation from communities in frameworks like React is that you should use JS and extra elements to polyfill that behavior. This is both less performant and less semantic. It really doesn't work particularly well if you're used to leveraging CSS in powerful ways.
Stuff like :first-of-type, sibling selectors, and so on are extremely useful. You give them up when you start manually attaching inline styles, and both JS performance and JS complexity to replicate those features will pretty much always be worse.
Doing animations in JS is usually a step too far even for the React community, so the recommendation I see there is often that you should define normal CSS classes and dynamically apply them. But now you're starting to mix CSS and CSS-in-JS, which is do-able, but can come with own set of subtle consequences. It also significantly lessens the benefit of CSS-in-JS, which is that you get to stop worrying about conflicts. It's not a dealbreaker, but it means you're somewhat back to managing the same name conflicts and typos that you were before.
I started out as much more open to CSS in JS than I am now. I was cautious about it and usually avoided it for personal projects. After doing a little bit more work on projects that use this pattern, I now feel like it's probably a bad idea, and advise other people to be careful about using it, even if I'm not willing to take a hard stance quite yet.
It's not that component-based CSS is a bad idea, I'm much more friendly now towards BEM than I used to be. And it's not even that CSS outside of JS doesn't have problems (the authors point about loading order is a particularly good example, albeit one that really shouldn't be coming up very often in a component based world. Also yeah, testing). I'm just less convinced that CSS in JS is a sufficiently scalable solution to those problems, or that it doesn't have significant problems of its own.
This may incur some additional runtime cost when the page loads (which is definitely nothing to dismiss), but should be (roughly) as performant as "native" styles after.
They still come with other disadvantages (and advantages), so I'm not saying you should definitely use them, but maybe you should take a look at some implementations you might not have seen yet.
Personally I arrived at the conclusion that they're not for me and that I'll just stick to SCSS.
Yeah, I would agree that dynamically attaching stylesheets is better than using the default React model for inline styles. I'd still be worried about the performance implications, but this might address a lot of my concerns.
I've also done animations in JS using react-motion and react-flip-move and had a pleasant experience with both.
const styles = theme => ({
main: {
padding: theme.spacing.unit * 2,
fontFamily: theme.fonts.primary,
...
'&:hover': ...
'@media (max-width: 600px)': ...
},
inactive: {},
});
You get the benefit of the nested structure per class... but the added options of easily establishing the classNames, which are computed to be unique, so no conflicts in practice. const FooComponent = ({ classes, inactive }) => (
<div
className={classnames(
classes.main,
{
[classes.inactive]: inactive
}
)}
>
...
</div>
)
In this way, you can bring in shared values from your theme. I can now inject different values into the theme from a central point in the application, via release, runtime, from an api/backend. I still have the option for psuedo selectors and media queries. There are more advantages with FAR less bugs than using CSS, even with SCSS/Less or other tooling.Stylesheets are then generated with dynamic selectors, and the selectors are applied to the component, and the stylesheet is injected dynamically.
To me, the biggest problem in CSS that makes me not completely dismissive of JS-in-CSS is scoping (although BEM does kind of tend to solve that problem pretty well for me already).
Dynamically generating the class names seems at first glance at least to be a good solution to that problem. Doing it as part of a compile step would be better than doing it clientside or serverside, but obviously that's not really feasible for most dynamic applications. Possibly there could be a Babel step that swaps out references in source code or something.
But yeah, I'm interested into looking into this more. Thanks for letting me know!
I believe there are options for many of them to run a pass through your components and generate CSS at build time, but I find that dynamically loading (react-loader) my components works out better overall, and don't notice the CSS generated at runtime in practice. I do inject a default style baseline that is enough for the app loader spinner, and the global error handler's output screen.
[1] https://github.com/cssinjs/react-jss [2] https://material-ui.com/
1. you can't inherit... 2. I don't want it in the same file...
// component.style.js
import base from '../base.style.js';\
export style = theme => ({
...theme.typography.body1,
...base.component.foo
fontFamily: theme.fonts.serif,
});
// component.js
import { style } from './component.style';
...
I'll see your objections, and raise you one... // theme-builder.js
import deepMerge ...
import { get } from './api-client';
export default async _ => {
const [base, client, application, user] = await Promise.all([
get('/styles/default'), // default options
get('/styles/site'), // client/deployment options
get('/styles/application'), // in-application configured options
get('/styles/user'), // in-application user options
]);
return deepMerge(base, client, application, user);
};
I'm currently working on an application that has those needs... doing that per-user means building styles at the server every time... using JSS, I just deepMerge some JSON/Objects and it all just works. I've built applications both ways, BEM, generated selector replacement, other techniques, and JSS... I'll take JSS.Devs doing front-end have this tendency to treat styling a page as some unsavory thing that they want off their plate as soon as possible. So they don't do any refactoring, and don't take any time to try to figure out the underlying concepts behind CSS. So you get these giant, append-only stylesheets that have no real rhyme or reason behind them.
Putting CSS in your JS has the side effect of hopefully forcing you to think more carefully about what rules go where. It's no magic bullet of course, but localizing all the code to one component in one file can make everything just a slight bit more maintainable.
There are real tradeoffs, of course. CSS in JS just isn't as mature as existing template solutions, and they don't yet let you do anything you want with them. Maybe it's a good thing.
For example: sending down only the critical styles needed to render a page. Many CSS-in-JS approaches get you this for free. If a component isn't rendered on the page, its CSS isn't on the page either. That can be technically challenging even if you follow the strictest, most disciplined patterns when writing your CSS in a traditional way.
Another is guaranteeing no naming clashes. You could be extremely disciplined, but let's say there are 80 developers working on different parts of your large site/application. How are they going to know that some other developer in another group isn't adding selectors for another component with the same name, even if it's a very specific name and follows best practices? Solutions that mangle the class names to guarantee uniqueness automatically fix this.
There are more, but those two come to mind immediately.
All things considered, CSS is a pretty good language. Selectors are a great query language, as long as your tags have well-expressed information.
CSS definitely needs something to address specificity, though. Maybe HTML needs an explicit tag or attribute to denote context, so that styles from higher level contexts would not apply to nested contexts. Purely from syntax perspective this could be addressed in CSS queries themselves, but I doubt such implementations would be efficient.
Another things CSS needs is some way to analyze it from scripts. It's amazing that there is no way to query/modify CSS rules from JS. It would solve so many issues with very little client-side code. You could implement CSS variables, for example.
I'm talking about interacting with actual styles. E.g.
let x = CSS.forSelector('article p').getRule('font-weight');
or maybe: let x = CSS.activeRules['article p']['font-weight'];
CSS.forSelector('article p').setRule('font-weight', '10'p);
You can fake the last one by dynamically generating CSS on the page, but that approach has many issues that would be avoided if there was a clean programmatic interface.With an API like this you could trivially post-process styles, extend core CSS functionality and even do some cool runtime analysis, like finding which rules aren't used on a page.
---
General CSS note. One thing I advise everyone to try is getting rid of any BEM classes for your components and replacing them with custom attributes. The idea is that each component (block in BEM) gets its own attribute and all the elements and modifiers go inside that attribute.
So instead of BEM
<div class="block__element block__element--modifier">
you get this: <div a-block="element modifier">
or this: <div a-block="element-modifier">
(By convention, custom attributes should always have dashes, so you never run into conflicts with core HTML standards and so that everyone can tell they're custom from the first glance. I never thought I would miss XML namespaces, but they sure would come in handy here.)Not only it's shorter and nicer to look at, it expresses more useful information and can be queried in ways that's impossible with BEM.
To use this, you need to be aware of the following CSS selectors:
[attr~=val]
[attr|=val]There is: document.styleSheets
It's existed for years, I remember fiddling with it in 2011 to dynamically change width/height of elements by changing the css rule from javascript.
Personally, I haven't run into any real issues with performance using advanced CSS selectors. But as with any performance statements, this applies to HTML, CSS and JS I worked with, on the browsers I tested with.
Sorry for the noob question.
.myComponent
is fine... but when you have: .myComponent button { ... }
.myComponent .x
and then you have conflicting rules, and your css gets overridden in unexpected ways. with JSS, the tooling can generate unique component selectors, and since it's all generated at a component level, you have less risk of applying conflicts.In particular: "Please don't post shallow dismissals, especially of other people's work. A good critical comment teaches us something."
If you want the most simple example, look at most apps based on bootstrap. They only start with the baseline/generated CSS, then apply hack patches throughout an application. Yes, you should use the source and generate yourself, for your application. But nobody does in practice. Even worse, a lot of the "bootstrap components" from third parties are also using hack css on top of the baseline, and require even more patches in actual structure.
I'm not bashing bootstrap, only pointing out how I've seen it used, which is poorly. Component based CSS in JS has even been a bit of an issue. Other developers on my team will put magic values into a given component instead of using values out of the theme that gets injected. I've had to go through again and again to correct this.
The difference is the former yields unexpected behaviors, while the latter is just a bit of inconvenience.
The former yields expected behaviors, and if you deviate, what do you expect? While the latter means that any time your product experiences a redesign, you have to manually change everything.
Not only do you manually change everything, and every component is isolated, you end up writing repetitive styles, and then you're stuck with a codebase with 5 different buttons, 4 different drop-downs, 7 different color schemes.
Nah, there's a reason why sites like Bootstrap Expo existed. CSS in JS doesn't just fail to prevent you from writing expensive to maintain code, it also makes it harder to evolve a product over time.
import baseStyles from './section.styles.js';
const styles = theme({
baseline: {
...theme.components.foo,
...baseStyles.foo,
// customizations here
},
variantState: {
// dynamically controlled style alterations for
// a different state
...baseStyles.variantState
},
});
You can totally reuse styles, it's just controlled at the component level. Beyond this, options for the theme itself can be injected by default, release, application settings in the app, and user configurable settings in the application. export theme = async () => {
const {env, app, user} = getThemes();
return deepMerge(base.theme, env, app, user);
};Lets say you have a SaaS project with a couple hundred individual routes, and you count them as individual components, you still haven't reached the magnitude you're talking about.
This keeps complexity of render components relatively smaller. I also don't mind breaking up compositional components for say NumbericInput, IntegerInput, WholePositiveInput, WholeInput, etc for form fields, each one with some entry filters in the component, and state level validation elevated to the containing component (and ultimately through form events, etc).
Beyond a lot of this, you have components with some display variances (subheaders that are shared in a given section of an application for sub-navigation, and some informative display), Most displays in the application I'm currently working on have about 5 shared higher order components (route level, header, section subheader, page footer, page capture/composition, data rendering, form input), and about 10-15 smaller/nested components just for rendering about half shared.
Across the application so far, there are about 200 components, with the application about 30% complete. The application itself is using react-jss as it's the base for styling with the material-ui component library. I've tweaked what gets placed in the theme a bit to pass additional configuration items into the theme. Portions of these additional options are part of a release configuration (per client environment/deployment), and part from flexible application options that are loaded from the API when the application loads, configurable within the application.
I've done similar things with dynamically generating base.scss files, and frankly the CSS-in-JS is far more predictable and easier to manage compared to prior applications using Bootstrap or similar SCSS/Less component baselines.
To just jump to an example of an extreme case, Facebook has stated several times they have tens of thousands of components [0]. Now, I assume lots of folks on HN work for private companies that build a wide swath of applications ranging from trivial to massively complicated. Why is it outlandish to think people wouldn't have many components in an app?
[0]: https://www.reddit.com/r/reactjs/comments/6al7h2/facebook_ha...
CSS is one thing and JS another.
It's typically better to use CSS for styling because it's declarative and simple. If your use cases are more complicated then use css preprocessors to resolve issues like variable names (something brought up in that twitter convo). If you want to do things at runtime then you need something procedural like js.
If you decide to forego css even for simple cases and use js because you think it'll be easier to maintain then obviously you'll need some tooling and conventions in place. If you have those, go for it.
If people want to put js in css (again, something brought up in the twitter thread), then that's fine too if various vendors supported it and there was a reason for it over js. There currently isn't, so again, I don't know what the hell we're talking about.
Also:
> The facebook codebase has thousands of !important statements, despite being written by competent engineers with solid engineering practices and deep relationships with design teams.
lol
"I'd rather assume other people are incompetent than accept that maybe maintaining tens of thousands of components presents unique challenges that I could learn from."
When I read the title of the submission, I immediately envisioned the typical "I thought we learned CSS belongs in its own file, why are web developers idiots?" comment.
Everyone is always trying to unmask each other as incompetent because it spares them the effort of being open-minded, of resisting the tempting repulsion of new thoughts, and of understanding why someone might prefer something else.
I don't think it's ever a good idea to bring into question people's competency when discussing software design principles. It's hard to quantify, difficult to verify and not usually relevant.
I am not assuming they're incompetent. I am disagreeing with the idea that their failure comes from just the technology and not in anyway from the actions of a developer. Whether it's because time constraints or just because shitty things happen like they do in any project regardless of how much money or how top tier the talent is.
Entirely disingenuous, and doesn't assume good faith by communicating experience.
> I am disagreeing with the idea that their failure comes from just the technology and not in anyway from the actions of a developer.
Exactly. More often than not, in fact a majority of the time, people are flawed when it comes to UI development. This underscores how greatly we undervalue good engineering. It's not some thing that's just commonplace.
As a barometer, not all of my coworkers are competent enough to build projects or products on their own that other engineers want to consume. In fact, especially when it comes to UI-related projects, almost none of them are competent enough to do so, and that's okay.
But it means I extend this criticism outside of the workplace, where I've worked at several companies where people could hardly take Photoshop renders and accurately replicate them in HTML and CSS, nor did many of them have an appropriate grasp of the visual formatting model.
CSS in JS generates the styling from JS at a component level. This has advantages of centralized theme/style and configuration values at build/deploy/runtime over other CSS generation options, while being every bit as flexible. There are many libraries with varied approaches. styled-compenents and react-jss are probably the two most commonly used.
Maybe learn a little about the subject at hand before spouting off and showing your own ignorance.
2) You can still have component level css files without using some kind of framework that puts css into js. I've written projects where there was an implicit organization of components where css rules would target components by having more specific rules. Like I said, there are reasons to have css in js. If the project doesn't require it, there's an argument to be made for keeping things simple by not including js dependencies for styling. Especially because in those situations it's not difficult to refactor the css into js.
> Maybe learn a little about the subject at hand before spouting off and showing your own ignorance.
ironic
You can either create some rube-goldberg configuration/generation for the entire application with complexity at multiple layers... OR ...deepMerge some JSON to deliver and have the theme/components use that.
I'm sorry, this guy is so far down the rabbit hole he can't even see the ridiculousness of his mental gymnastics.
We've had to ask you this more than once before.
You think you're being the "sane one" here but it's comments like this that turn every discussion about a polarizing topic into an equivalent of a bar fight. Get your stuff together.
Reminds me of this piece of history (how to set focus on input field in AngularJS): https://stackoverflow.com/questions/14833326/how-to-set-focu...
> Things like that (CSS into JS/ typed JS/Elm) are done because the developers are not competent enough in their field, and instead of learning about it, they try to create their own solution for it
Broadly calling developers incompetent because they've developed/use tools that you don't like is not "disagreement," it's just an ad-hominem. It has no place in a technical discussion.
When the OP replies that he can do that in CSS or Sass, smart guy then moves on to new argument - naming.
Reading interactions between 2 people with different well reasoned opinions on the same issue is fantastic and can be illuminating.
Reading curt regurgitation from people who don't have anything worthwhile to add to the convo is beyond frustrating.
EDIT: What I mean here is that the foundations of the web weren't designed for application development and are missing some crucial bits and pieces like encapsulation. The tooling necessary to encapsulate CSS in a way that works with every browser is complicated, and if you've only worked on small to medium projects it can be hard to see the need for such complication.