Hacker News new | past | comments | ask | show | jobs | submit login
Re: “‬How does writing CSS in JS make it any more maintainable?” (gist.github.com)
125 points by playpause on Dec 14, 2018 | hide | past | favorite | 144 comments

Having tried every alternative imaginable, component based CSS is the way to go. There's a legacy in web development of viewing CSS as something separate from structure and logic because of what the web used to be; a collection of static pages with style sheets for typography and layout. But as soon as you start building any kind of non-trivial application, this model breaks down. The only way to do it is small, atomic, composable components with fully self contained styles and minimal inheritance.

because of what the web used to be

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?"

>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.

> it's the only way to structure UI for an application

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...

Here's roughly how I do it[1] ...

    import Button from '@material-ui/core/Button';

    export MyComponent = ({actions}) => (
[1] https://material-ui.com/demos/buttons/

In fact inline styles came first!

> 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.

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.

I think his point was more that we're developing the web building over foundations set with the idea of static documents in mind, for far different use cases that were originally intended. It does raise a point over whether we should consider a new design.

I think the real issue is people ignore CSS while building applications. You see the same issue when people try and the database or other critical component. That always results in a hacky mess that gets worse over time.

Know your tools.

Netscape had CSS in Javascript in 1996


And they had server-side JavaScript a year before that: https://hacks.mozilla.org/2012/01/javascript-on-the-server-g...

Could you elaborate on what component-based CSS is for the uninformed? A cursory Google search indicates that it's a technique for using CSS in JS, but I'm not sure how I would go about doing it. Does it imply some web component framework?

>Does it imply some web component framework?

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:


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.

This is easily done using SASS components as well. No framework needed.

It depends on how you want to structure your app.

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.

All of our components are contained in a folder specific to that component, and include the JS (Vanilla ES6), SASS, and template markup.

Perhaps something like Styled Components?


It's not super complicated, just apparently controversial.

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.

Not a FE dev, so this may be naive but CSS cascades which means these components may rely on external css state. How is that handled and still qualify as self-contained?

In practice nested behaviors, or class/id selectors will conflict. The more you rely on generalized stylesheets the harder it is to maintain. I've been developing mostly web based applications for 23 years now (started before CSS).

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.

I've been developing mostly web apps for a long time too, 17 years, and I disagree. Well, I agree that a single, massive stylesheet file becomes difficult to maintain very quickly, but that or component based CSS that eschews inheritance are not the only ways to go.

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.

Right now, the application I'm working on supports the following feature in terms of styling/colors. Baseline settings, per-deployment/client settings (app deployed to different clients with a differing configuration), app configuration post-deployment configurable settings application wide, and post-deployment configurable settings per user.

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.

There are also CSS modules that are a middle road between CSS in JS and classic Sass stylesheets.

When you render your components, you do so in a Shadow DOM where CSS neither enters nor leaves.


I prefer material-ui [1], a material design component implementation for react. It uses react-jss with some plugins under the covers. It's been very intuitive to use the global theming combined with some options.

[1] https://material-ui.com/

Instead of having files that apply styles globally to your application, the styles live down in files or data structures as close as possible to the component it applies to, where it belongs.

I've been trying to tell this to people for years:


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.

Component-based CSS using Interoperable CSS + Sass, importing your CSS into JS but then using a build system to extract all of your component CSS into it's own set of files to allow for caching.

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.

The only way to do it is small, atomic, composable components with fully self contained styles and minimal inheritance.

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?

What about sass modules? Independent .scss files per component, with no class name clashes. Or are you counting that as css in js?

Do you class your sass like `.fooco-app-area-feature-component {...`? Because you have to be extremely judicious when you do. You also have to be very careful of nested behaviors.

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.

I use SASS in my React app, but it runs with CSS modules in webpack so you have no worries about class name collisions. It will rewrite a class name like 'wrapper', to 'MyComponent_wrapper_<shortHash>'.

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.

Another issue is constants that need to be different based on deployment, or configurable in an admin section of the application.

> Do you class your sass like `.fooco-app-area-feature-component

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}’}

And when you want one color for one deployment of your application, vs a different color for another deployment?

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).

> And when you want one color for one deployment of your application, vs a different color for another deployment?

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.

And when the variables are configurable in the application? then the options are...

    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.

So when you have user configurable sass variables, css in js might make things easier. That seems like a fairly narrow use case, I’m not willing to sacrifice separation of styling everywhere in every component in every react app because it makes user defined style variables somewhat easier.

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.

You can still inherit baseline styles via a common theme that gets injected... See material-ui[1] which uses react-jss[2] configured with appropriate plugins, being able to customize components using said theme is far easier than any SCSS setup I've used. It's really, really nice to use in practice. It's just a slightly different syntax, and if you REALLY want to, you can still put your styling config in a different file from your component rendering.

[1] https://material-ui.com/ [2] https://www.npmjs.com/package/react-jss

This is exactly what we do, and suffer zero issues. You have the globals (color scheme, typographical rules), and then you have the component-based, scoped SASS.

I don't see any reason to do it any other way, and it scales just fine for the systems we build.

CSS in JS turned into a nightmare in our project once we decided to make it fast. CSS in JS usually do next things for each component mount:

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.

We've not run into any performance issues in our 80k LoC JS app using styled components 100%. I'm not sure it's accurate to say it's ditched static styles exporting, with babel-plugin-styled-components we're getting a handful of style tags on the page that are generated at build time.

Not sure about your stack, but styled-components declared it as deprecated and babel-plugin-styled-components page doesn't show anything about static style extractions.

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.

Not sure where you're getting that it's deprecated. Both the repo itself and the styled components website list it as a highly recommended (but optional) addition.


Plugin is not deprecated, sure, but it doesn't do static style extraction:

`This plugin adds support for server-side rendering, minification of styles, and a nicer debugging experience.`

I've been using material-ui which uses react-jss, and that has performed more than adequately for our use case.

Can you give an objective example of the magnitude of difference in performance?

We have built our own jsxstyle-like library and we got about 10-100x improvement.

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.

So we have gone back to the days of Java and WinForms where everything from the UI layout to styles to business logic was in the same damn language in the same damn file and many times in the same goddamn function.

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.

It's not quite the same... styling conventions can still be followed, inherited style structures can also be passed from a global theme, or higher order components. You get the added advantages of a more flexible configuration that more easily integrates with the rest of the application as a whole.

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.

> It's much harder to generate different global values for $primaryColor and related in scss for different deployment targets.

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.

with JS, I don't have to change the JS entry point, just set a different environment variable... I can also compose nested rules into one configuration set. I can also dynamically inject into that configuration at runtime via application/user control settings.

> inherited style structures can also be passed from a global theme, or higher order components.

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?

Okay, so you want a global setting for buttons...

    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.

As to the last part... lets say there's an application default for $someVariable, a per-client optional override, an application configurable (runtime database) override, and a user-level override.

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.

And as far as I am concerned that was goddamn great. No, not that these things were in the same file or function - there are ways to separate that, but I miss the days when I could do it all in one language with one tool chain instead of three.

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.

As a former purist who's adopted the styled-components implementation of CSS-in-JS, I can say 100% that maintaining styles has become an absolute dream. It's not terribly different from CSS (meaning, if you need to extract a stylesheet it's just a few lines of code) and its ability to do autoprefixing and Sass-style nesting out of the box is a massive time saver. Coupled with CSS variables, it's an ideal toolset for authoring styles.

I've spent over a decade fighting with CSS. Sass was a welcome upgrade. CSS-in-JS is a welcome next step.

What's the advantage to this over sass modules? You have the same scoping but with better separation of concerns, that seems the superior choice.

The big difference is with run-time styling changes when communicating with an API. We ship an application as a whitelabel where our customers define their theme through Contentful. With CSS-in-JS, converting the entire app's theme based upon XHR is trivial.

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)

I used to think this way. In reality, you're not separating concerns, you're separating technologies (CSS and HTML).

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.

Logic, layout and style are inherently separate parts of a component. Separate concerns in other words. Ideally they should have separate definitions. This is the cleanest and most maintainable structure.

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.

What separation of concerns?

    // RenderComponent.js
    export default props => (
      <div class="foo">
        <button ...>...</button>

    // 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.

The biggest one? Not having to wrangle class names. Like the author points out here, that becomes increasingly difficult over time. Sass is wonderful (I still rely on it in some older projects), but when I'm working with JS/React, CSS-in-JS just feels smoother and tidier.

Sorry but I don’t get what you mean, and I can’t see where in the article you are referring to. What do you mean by wrangling with classnames? Do you mean clashes? That’s what modules do, they scope your scss so that you don’t get clashes between components.

I'm going to assume that SASS Modules are a SASS adaptation of CSS Modules, because it seems like "modules" might have multiple meanings in the SASS world? So please tell me if this is wrong!

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.

Thanks for the explanation. Yes that’s correct, it’s the same concept as css modules but with scss instead of css.

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.

> Also, with css in js I believe that pseudo elements and animations are an issue

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. :)

Ah, wasn't aware of that existing. In that case then I suppose it's just preference. I'm sure there are other nuances but not something worth mucking with since I'm happy/productive with CiJ.

> Further, it’s extremely hard to statically analyse selectors to see whether any rules are broken (or even a typo!) this means constraints have to be enforced via code reviews and education, which is a harder problem to solve and scale. We should use a computer's assistance us on this, and not rely on humans being infallible (they’re not!)

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.

I use CSS modules coupled with postcss (mainly for minimization and autoprefixing) and sass-loader almost exclusively. The one benefit from CSS-in-JS I can think of is when the JS needs to know of a value that would otherwise exist in CSS only.

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.

CIJ also has the advantage of being able to more easily inject different configuration values for different builds/deployments... Client X deployment has a primary color of blue, client Y is red. And it can go much deeper where a theme is used globally and each component creates its' own styling based on that theme.

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.

You can use CSS Variables to bridge between.

   var style = getComputedStyle(document.body);
   :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.

Seems like a rather ugly hack to reverse-render values out.

CSS Variables seems to be very useful for CSS. I am not sure if changing dynamically CSS variables from JS is a great idea but you have options to do so.

There is more coming in project Houdini. https://developers.google.com/web/updates/2016/05/houdini#th...

for your specific example - you can declare SCSS variables in a JSON file, that makes the definitions accessible to both JS and SCSS.

This sounds pretty interesting, thanks for sharing. Do you have an example you can share? Are you using node-sass-json-importer?

Using sass-vars-loader for this which is a webpack plugin: https://github.com/epegzz/sass-vars-loader

I strongly disagree with the CSS in JS movement, because philosophically it gives false hope about isolation. The thing is, no matter how you try to isolate a scope, things are going to cascade! You could have someone above you change the font weight and not visually QA all your code paths, and now your subcomponent's entire layout could be messed up. BEM, SCSS, and standardized namespacing get you 90% of the way there, and force you to think about the cascade when writing.

I disagree with it for another reason. I'm tired of developers solving language design problems by piling on more and more complexity, tools and libraries. This is a self-defeating approach, because those tools and libraries often have their own issues, and instead of fixing those, people pile on even more tools and libraries. The process goes on and on. It may feel like progress, but it doesn't really go anywhere.

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.

The DOM has styling primatives... many CSS in JS libraries use them... others compute CSS from the JS object structure used to define (based on JS DOM interfaces for styles).

You can definitely handle potentially cascading issues with styling...

    const styles = theme => ({
      myComponent: {

One major problem I've run into is that CSS in JS usually lacks support for pseudo-classes and browser breakpoints.

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.

I think you're missing an important point. Not all CSS in JS solutions attach styles as inline styles. Some of them, such as Styled Components [1] and Emotion [2] (and many more) will actually generate proper CSS Stylesheets and attach them to the document, thereby enabling usage of all CSS features—including, for example, pseudo-classes.

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.

[1] https://www.styled-components.com

[2] https://emotion.sh

You're right, I didn't know that there were solutions that took this approach!

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.

We use styled-components, which is one of the most commonly used css-in-js libraries, and it supports both pseudo-classes and browser breakpoints. I'm not sure how applicable this argument is, my experience runs counter to the premise.

I've also done animations in JS using react-motion and react-flip-move and had a pleasant experience with both.

JSS (react-jss) has a couple plugins to handle this very well, and allows for nesting similar to scss/less.

    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 }) => (
            [classes.inactive]: inactive
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.

This strikes me as a much more sane approach, which makes me really surprised that somehow I haven't heard about it until now.

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!

There are different CSS-in-JS libraries, I'm using react-jss[1] myself, which is the example... I'm also using it configured via material-ui[2] component library which has a couple addons for nested structures, psuedo-selectors, media queries etc.

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/

Pure the use of JS vs. CSS is not what makes CSS-in-js more maintainable. It's "scoping styles locally to a component" that makes it more maintainable. As well as having easier interaction between them, like theming or dynamic behavior.

Regarding most of the dismissive comments on using JS for styling...

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 => ({
      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.

It doesn't. But what it can encourage you to do is to stop writing CSS that has effects outside of the component it's attached to.

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.

While that is a benefit, I think that's underselling it a bit. It certainly enforces more organization & discipline, but some benefits are more concrete and technical. :)

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.

Agreed, thanks for elucidating.

Moving CSS to JS because of selectors? Hm, I often do the exact opposite. I effectively move JavaScript logic into CSS queries and data into corresponding tags/attributes. When I started doing that, my scripts became far more enjoyable to write, trivial to reuse across projects and orders of magnitude easier to analyze/debug (just run the query and see what it finds, mostly).

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:


> 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.

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.


According to the standard, custom attributes _must_ begin with 'data-'. For example, `data-a-block`. Of course, it still works if you omit 'data-', so I fully expect that this requirement will be changed to "must contain a hyphen".

What about performance when relying so heavily on this string matching with attribute selectors.

What about it?

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.

In about 5 years, we're all going to be on inline styles in JSX (or equivalent), flabbergasted that we ever thought CSS was a good idea. Calling it now.

Next on HN: Why Javascript is the future of voting machines

Css is a write only language. There is no read mode.

You can read it the browser using the developer tools; 99% of my reading of CSS comes from there. I add/tweak in the browser and then I go to the source and re-apply the changes there.

How do I blacklist my own urls from this website?

Short answer: It doesn't unless you follow some light "Design by Contract" principles... unfortunately that flavor never really caught on.

I find that the people with the most vitriol reserved for css-in-js concepts tend to be those who have exclusively developed front ends for the web and never on any other platform. I wonder if others have made the same observation. Perhaps they should expand their minds.

The alternative is imperative UI design à la Win32, so I'm not sure what there's to expand on. Unless you really think writing a couple hundred lines of code to set position and apply event callbacks is a good idea.

Is scoped CSS different from CSS in Js?

Sorry for the noob question.

Yes, all CSS operates via selectors... scoping generally means applying a className to a component, and then generating all CSS for children relative to that. The issue at play is when you start nesting, or using components together, and child naming blows up.

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.

I'm always curious about what the largest magnitude of a UI codebase someone has maintained when they make comments like this.

Would you please stop breaking the site guidelines? You've done this many times, we've asked you repeatedly to stop, and you keep doing it.

In particular: "Please don't post shallow dismissals, especially of other people's work. A good critical comment teaches us something."


I'd like to see you maintain a codebase of thousands of components with CSS in JS vs another management solution via CSS build (like scss) and see how many buggy/hacky issues you have with each. I've worked in codebases of significant size managed both ways.

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.

This isn't even a statement about either technology, it's just a commentary on bad developers, and trying to alter or minimize the damage they do because they're bad, using a different technology.

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.

You can share style portions at the component level.. you can bring in portions of style definitions from the parent or even the theme level...

    import baseStyles from './section.styles.js';

    const styles = theme({
      baseline: {
        // customizations here
      variantState: {
        // dynamically controlled style alterations for 
        // a different state
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);

Uh, bullshit? Thousands of components? Yeah, okay. You create a single new component for every permutation, route, and derivation? Where are these projects with thousands of components? What open-source projects can we use for reference? Are they all commercial and therefore private? That'd be convenient wouldn't it? Bootstrap lists 21 individual ones, not counting layout, content, utilities, or other classes.

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.

I separate a lot of if/else components into a logical component and a render component. Now only the render components have styling, but they can share common style configuration, usually through a theme that's injected higher up (react-jss).

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.

I don't think equating 1 route = 1 component makes much sense. A route could be as simple as `/user/123` which shows an avatar and a name, or it could be `/billing` which has many sub-routes and complex features behind it.

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...

The author works at Facebook. I'd argue that Facebook's UI is pretty complex.

Sunil has also worked at Yahoo on maps.yahoo.com, specifically on tooling to manage styling.

Honestly, what the hell are we talking about here?

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.


> 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."

You can click into any web-dev related discussion on HN to find someone trotting out their thinly-veiled assumption of "everyone is incompetent except for me".

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.

lol because it's a meaningless statement not the least because it implies smart people always produce perfect code.

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.

> "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."

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 does NOT put JS in css... there have been other efforts to do things like that.

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.

1) I never said css in js puts js in css. I don't even know what this means.

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.


Okay... now add in the ability to have a Default color... add in the option for that color to be overriden for a given deployment. Now add in options to have a style setting configurable application wide in the application. Now add in the option to have a configuration option per-user.

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.

"In an SPA/component world, where assets like scripts and styles are loaded asynchronously, you can’t guarantee style sheet loading order, which means you have to lean on some form of runtime composition to guarantee a shape, else you end up with !important rules even if you follow a given architecture"

I'm sorry, this guy is so far down the rabbit hole he can't even see the ridiculousness of his mental gymnastics.

Personal attacks will get you banned here. Please review https://news.ycombinator.com/newsguidelines.html and don't post like this to HN again.

We've had to ask you this more than once before.

Is there really no way to have a technical discussion without being hostile? You could, for example, reply with the actual things you disagree with.

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.

How would you have phrased GP's point to make it more acceptable?

If you remove the ad hominem from it, there is no point left at all. I could find another phrasing if it contained any substance.

Long answers to simple things is a sign that there's something wrong.

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...

I'm curious what frontend problems you have solved to be able to know that this is ridiculous and have to start a personal assault against the author of this comment?

Given that one of the benefits of these approaches is that styles are scoped to components, i don’t see how load order can be a concern

Because two stylesheets base.css and mytweaks.css might not load in the order you want even if all the rules are scoped? And at that point you're already using something like webpack to enforce the order you want, why not just make JS do it?

I consider the goal of scoping styles is to not require overriding styles, in which case the order shouldn't matter... perhaps that's not practical in all cases but it's worked for me so far.

The thread makes me want to quit the industry. One person disagrees and gets "I vote for this statement to be nominated for Worst Sentiment of 2018", while the gist-er is congratulated with "instant classic" and "you're my hero." The JS cargo-culting insanity is becoming unbearable and dissenters are mocked as noobs.

That "worst sentiment of 2018" comment was directed specifically at

> 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.

My favourite from that thread is somebody trying to be smart & pithy leaving a link to the wiki page on 'Composition over inheritance'

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.

In my 2 years of experience, this guy does not represent "the industry".

Just get off the front end. Things are pretty sane everywhere else.

I stopped doing front-end dev for this reason. I told my manager I no longer wanted to do anything on the front-end, and they were fine with that. Since I've gone 100% back-end only, my work life has been far more sane.

Agree. I'm trying to right now. I think it has more artsy types, which means more drama.

I think it's because SPA web development is like using a hammer made of chewing gum to build a house, and the ridiculous toolchains necessary to build a solid hammer always look complicated and unnecessary.

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.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact