Hacker News new | past | comments | ask | show | jobs | submit login
Why I Write CSS in JavaScript (mxstbr.com)
195 points by bpierre on Feb 18, 2019 | hide | past | favorite | 249 comments



Imagine a programming language that only had global variables.

You have to carefully name your variables using complicated conventions in order to avoid any conflicts or unexpected behavior.

Even your functions don't have local variables; there is no lexical scoping. Any function can overwrite or mutate what any other function is doing inside. There is no real encapsulation.

After you've done this perfectly, your application gets bigger and you start wanting to reuse third-party modules made by other developers, because they've already solved some of your problems.

Uh-oh: they didn't follow exactly the same conventions, and now things conflict. Or their variable names were perfectly unique in their own code base but not when combined with yours (or when combined with several other third-party modules).

This language is CSS and is why people are so fed up with selectors. Even "scoped" selectors really aren't lexically scoped in the sense that other languages handle scoping... it's still just another naming convention hack.

I use CSS-in-JS because CSS wasn't designed to be a language that survives attempts at modularization, third-party code sharing, etc. No sane programming language attempting this would only have global variables. So, we throw out the selectors part of CSS and keep the rest, at least for now.

Nobody using CSS-in-JS thinks this is an ideal situation. Nobody wakes up thinking, "oh my god, I need to put my CSS in my JS, it would be perfect." We're just trying to deal with the hand that's been dealt.


This is sad. All because people are not able to think of one simple prefix and stick with it when naming CSS classes. How hard can it be? Just use some part or abbreviation of the company name and be done with it. Or better yet: Let third party do that. I always hated that, when someone used Bootstrap on a website and Bootstrap f'ed up all future styling, by assuming it was the only one player in the game. So stupid.

I personally never ever ran into any problem, when I myself named CSS classes and that is because I automatically think about the future and whether a name could conflict with something else, instead of being lazy and typing 3 characters and thinking I did my job. I am simply careful and use prefixes and give unique names, so that it has such a low chance of someone else using that CSS class name, that it simply never happened in practice. So from my personal experience all that mumbo-jumbo about CSS name collisions comes from people not being careful and is a "house made" problem, not a problem of CSS. I never had any need to use JS to do what is CSS's job.

Using JS for doing something CSS should do is furthermore dangerous, since clever people deactivate their JS or block it partially. For me personally, your (not you personally, but you in general, anyone who reads this) JS better comes from your own domain, or it will be blocked by default. If you can live with people seeing your website utterly destroyed by its inability to apply style, then OK, do the styling in JS.


I'm happy that just prefixing things is working for you. I don't typically have problems on smaller projects.

But I've also been writing CSS since 1997. I've deployed CSS to sites like walmart.com, nfl.com, mlb.com, starbucks.com, twitch.tv, etc. Some of these sites have a lot of third-party widgets on them. I can confidently say that the (multiple) issues with CSS are not a "just do <simple thing X>" type of problem.


> I can confidently say that the (multiple) issues with CSS are not a "just do <simple thing X>" type of problem.

I'd go so far to say that almost no (real) problem is that type of problem. Maybe problems that are mostly inconsequential, sure.


People want an interface such that a folder represents all they want to know at that moment about a component. But then someone else may want an interface such that a folder can represent all the styles across the app.

Otherwise I do think that the naming collision problem is really easily fixed.


You can get the beat of both worlds by having one folder for one component and then a ‘common’ folder.

SASS seems to solve most of the problems i would have with writing basic CSS.


This is the goal of Web Components / Shadow DOM.

Angular implements a polyfill for this. Every angular component has 3 files html, ts, (s)css, and the styles in the components css file are automatically scoped to just the component they apply to. It takes away all the stress of global css selectors, and if you want to share styles you can just have a library of shared styles and import them via scss. It's honestly heavenly and I haven't thought about conflicting selectors in years.


I'm aware and agree, and it also – even if less so than other solutions like Styled Components – counts as CSS-in-JS. So welcome to enjoying CSS-in-JS :)


Or use Polymer/LitElement, where it's just all in one file... I swear people are just reinventing react methods to eventually get to where Web Components have been for the past 4 years.


React is greater than 4 years old, and people mostly use it for the nice authoring experience, not to dick around with CSS isolation problems.


You don't have to "dick around" with CSS isolation problems with web-components, it just works. React is where you are dicking around.


I agree CSS has problems. What I don't see is how styles-in-JS addresses them.

Very typically, for a given app and page the styles of individual elements and components are not independent. They also depend the app theme, app section, layout area, component group, etc. The element fits the component. The component fits into the section, the section fits into the page. The specific relationships in a particular case are different of course. Styles are visual and the idea that a component on a page has nothing visually to do with the rest of the page is wrong.

The typical scoping rules of programming languages doesn't fit that well here.

To the extent some styling solution encourages you to treat styles that are dependent as independent, that's not a good or useful thing.


A lot of CSS-in-JS libraries provide a theming solution, e.g. [1], so it's not an 'either/or'.

(You can also relatively easily implement your own, because JS :))

[1] https://www.styled-components.com/docs/advanced#theming


Sure.

My point is, when it comes to visual styling, you inherently have a shared visual context.

The post I was replying to was concerned with the "global" nature of CSS.

I'm pointing out that this is inherent to the problem space. You have to deal with it whether you use CSS, code or any other mechanism to style.


Nobody in the CSS-in-JS world is disputing that a global theme is useful, just that having no choice but to have all your selectors be global is not so great.


I don't entirely understand why some people find CSS so difficult to work with. I agree that it has its own challenges, but solutions generally aren't very complex. Global selectors ("variables") collisions? Use namespacing. Specificity is convoluted? Simplify by using only non-nested classes.

Does the annoyance primarily center around the fact that styles cascade to child elements? Hard to tell from the article.


Good software is reusable. I can import functions from 1,000,000 different npm modules all into my project and they don't fuck with each other, right?

Let's say you wanted to pull in a button from Bootstrap for one part of your page, a button from Material UI elsewhere, a button from Semantic UI elsewhere, etc.

These things are made to be reusable right?

What are the chances you can do that without issues? Do you think any of their style rules/selectors would clobber each other? What about the base/assumed CSS that they all most likely require? What about components more complicated than a button? Without actually trying it, how much confidence do you have in your guess, vs. your assumptions about importing other things (like functions from npm modules)?

Good software is reusable without worry.


> Good software is reusable. I can import functions from 1,000,000 different npm modules all into my project and they don't fuck with each other, right?

I just spent the whole day trying to fix compatibility issues between different versions of npm libraries transitively imported in a project. Reusability in JS is a joke.


Agree.

As a primarily JS/React developer, I think there is irony if JS is held as a good design pattern in comparison to CSS with respect to reusability. Inasmuch as what are being called CSS "workarounds" are in fact workarounds, so too has been the case with JavaScript itself. I am old enough to remember jQuery and Prototype colliding over the dollarsign namespace.

Don't get me wrong. I am not a JS (or CSS) hater. I think these "workarounds" are more than adequate in making these technologies easy to work with. Which I suppose is sort of my point. I see a lot of overengineered codebases with Byzantine solutions to relatively simple problems.

Also, to parent poster:

> Let's say you wanted to pull in a button from Bootstrap for one part of your page, a button from Material UI elsewhere, a button from Semantic UI elsewhere, etc.

1) First of all, don't do this. Perhaps you were just saying this to make a point, but obviously don't include 3 monolothic libs with overlapping functionality in order to implement 3 things with the same functionality.

2) It sounds like your problem with this is more with the libraries themselves. When I write a component, I always namespace it myself. Obviously, if libraries are properly namespaced, then you could easily include buttons from three separate button libraries.


What dependency system anywhere on earth is free of the problem of "two things require different versions of the same library"? I don't see the relation to JS at all.

I've had this problem with JavaScript-before-npm-existed, Python, apt, Homebrew, Portage...


stack for haskell

nix package manager


Note that npm also supports having multiple versions of the same package installed just fine.

The problem:

I use X to create an object with library A v1.0.

I use Y to create an object with library A v2.0.

These objects are not necessarily compatible, so X and Y have problems communicating.

I would be very surprised if you told me nix or stack inherently make objects from multiple versions of the same library magically compatible with each other.

Feel free to close issues like this one if I'm wrong: https://github.com/NixOS/nixpkgs/issues/30551


Hmm I think this should go something like this:

How would objects created from X and Y can reach each other and communicate when X is not dependent from Y or otherwise? You need global mutable state or your own code witch depends from both X and Y is somehow connecting them.

So one top thing FP movement argues against is global mutable state so of course you don't have that ...Unless you are wrapping some non-FP thing like QT...

And if it's your own code it shouldn't be different that Y creates B:s instead of A v2 since your code is aware from two different versions anyway.

Do you see any weak points?


CSS is not a programming language, and it shouldn't be viewed or compared as one.

It has different functionalities.


It's a language either way, whether you consider it "programming" is not really important. So, good luck with that.

I live in the real world where it's used almost exclusively by programmers.


CSS is a tool used by web developers to style their websites.

Whether technically it's a programming language or not is tangential.


People implement Doom in CSS. It's clearly more than just some style notes for the browser.


I think you may be confusing that with something else. You can't create a complex game with just CSS. I'd love to be wrong but provide a link.



The first one looks like a big part of the functionality is from the JavaScript file. It's crashing my iPhone so I'm having trouble digging into it too much. The second link, however, does seem to be done in pure css. Impressive! Thank you for the links. I stand corrected.


That limitation is why people like the article writer often replace it with a programming language.


It's not a limitation. It's different.


It is absolutely a limitation, because there are things you can express in other languages that you cannot in CSS.

But a limitation isn’t necessarily bad, and is often good. Finding the language of least power (ie it is just powerful enough to express the sorts of things you want, and no more) is very useful for safety and productivity, but in CSS’s case it seems like it’s no longer powerful enough to express all the things its users desire.


It is both. Whether you consider that a good or a bad thing is an entirely separate issue.


Its different and it a poor lang. The only people advocating for css only are privacy freaks. They're often the least return producing customers, hence ignored.


As far as I understand there are very good sides of CSS, as a declarative constraint language. More than being a poor language it looks like it is hard to use it for modern web development.


> The only people advocating for css only are privacy freaks.

This just is not true. It may be your opinion, but it is objectively false, particularly in the context of this discussion.


Isn't CSS (with HTML) Turing complete?


As far as I know, Turing completeness isn't essential for being considered a programming language.

SQL is one, HTML too.

They both tell a computer what to do.


HTML is not a programming language, it's a markup language. And SQL is Turing complete.


Coq is a good example of a non-Turing complete programming language.


I don't know. I've seen people do some crazy things with pure CSS that look quite a bit like programming.


On the flip side, after using CSS in large projects for years with many, many third party libraries, I've never once felt this urge... Rarely had any problems. At least none that the effort of styling everything in JS would merit!


Not a solution for CSS I guess but if I was using a programming language that had only global variables I'd write a compiler to generate variable names.


It is a solution for CSS, and it's called CSS Modules.


and it counts as "css in js"


To me the real problem is javascript. It makes stuff like this so easy that no real solution has come along. Worse is better, I guess.


Emacs lisp is pretty much like that. Nowadays it does support semantic scoping but lexical scoping is still very useful.


I don’t really understand this comment. Emacs lisp always had dynamic scoping, which is a bit more than just global scope because you aren’t quite stomping on top of other variable bindings. You get resetting your bindings to what they were before you started for free and you don’t need to worry about nonlocal exits. Emacs lisp also has macros and gensym to avoid some of the pain of name clashes.

Emacs lisp also has lexical scoping. It optionally had it for a long time using cl.el with lexical-let and friends. It now has it as a file-local variable read by the compiler/interpreter.

I also don’t understand what you’ve written at all. You say “Nowadays it does support semantic scoping” but semantic scoping isn’t really a thing (as you next write lexical scoping, I assume you mean dynamic scoping), but the words “nowadays,” “but,” and “still” imply that you are talking about the new kind of scoping (ie lexical) and comparing with the old (dynamic, which you cal lexical???).


It's part of what makes Emacs so easy to customize on-the-fly.


CSS isn't a programming language, that is the fundamental difference and explains a LOT of the debate surrounding it.


Does not classifying it as a programming language help this situation at all?


LocalPCGuy may just be responding to the grandparent comment which claims that it is:

> Imagine a programming language that only had global variables. You have to carefully name your variables using complicated conventions in order to avoid any conflicts or unexpected behavior. Even your functions don't have local variables; there is no lexical scoping. Any function can overwrite or mutate what any other function is doing inside. There is no real encapsulation.

That simply isn't true; CSS specifies a bunch of declarative rules, which statically evaluate. Though the evaluator may be stateful, reasoning about how the properties for each document node are determined doesn't require state. It requires reasoning about the targets of the rules, and when they overlap, about their relative scopes and priorities.


I am the grandparent, and never mentioned anything about state. Not sure why state matters. Declarative CSS rules have effects. The scope of those effects can be both unlimited and unintended, and you can't "opt out" of being affected by rules – if some rule is targeting you, you're out of luck, unless you anticipate it and apply everything with the greatest specificity possible.


Pardon me; I was thrown off by wording like "overwrite or mutate".


And HTML is a markup language for hypertext, a document rather than an application.

But it turns out that we're using it and CSS and JavaScript to build full blown applications. So, because we're trying to solve problems with applications rather than documents, we have to map the problems of application programming onto it.

So, to build an application, we run into problems CSS wasn't designed to solve (being a not-programming language.) Whether it is or isn't a programming language is irrelevant - to solve our problems (writing applications), we have to treat it as if it is.


This is one of the reasons why I don’t like web development. Here’s how MS solved this in XAML, a markup language used in Windows world for GUI:

  <StackPanel>
    <StackPanel.Resources>
      <Style TargetType="TextBlock">
        <Setter Property="Foreground" Value="Red" />
      </Style>
    </StackPanel.Resources>

    <TextBlock Text="Red" />

    <StackPanel>
      <StackPanel.Resources>
        <Style TargetType="TextBlock">
          <Setter Property="Foreground" Value="Green" />
        </Style>
      </StackPanel.Resources>

      <TextBlock Text="Green because the default style was reset by the nested container" />

    </StackPanel>

    <TextBlock Text="Red again because the nested container scope has ended" />

  </StackPanel>


You can get basically the same thing from rebass in JS:

  <Box
    p={5}
    fontSize={4}
    width={[ 1, 1, 1/2 ]}
    color='white'
    bg='magenta'
  >
    Box
  </Box>
It uses a CSS-in-JS library under the hood to translate that into a CSS class for each unique combination of styling props.


I find this extremely hard to read. I mean I can see the advantage, but there must be a better way?


I agree on readability, CSS is much more compact, and therefore easier to read. I think MS designed XAML to be mostly handled by tools not humans. Didn’t work because the tool (expression blend) is not quite good enough so humans have to deal with the source too. Experience helps for simple cases like this one but not for more complex cases like control templates or animations.

I’ve wrote the above example because it shows a possible solution to the stated problem, i.e. how to introduce namespaces for styles without also introducing a full-blown programming language with scopes and variables. The exact syntax can be replaced making it more compact and easier to read.

Compared to this mostly-immutable scoped dictionaries, way more things can potentially go wrong with code, regardless on the programming language.


I understand the "pit of success" idea, particularly when it comes to more junior devs. But I don't necessarily agree that you need stringent processes to get most of the gains you cite from using something like SCSS or even regular CSS these days. It's really easier than ever.

1- append only? No, each module/feature/widget gets its own CSS file, imported to the main app CSS file. Delete the widget? Delete the file.

2- Specificity issues? Never use IDs, stop using tag names and simple classes and adopt a simple naming structure (doesn't have to be BEM, it could literally be ".widgetName-header")

Since I adopted those 2, I've almost never had dead CSS from deleting features or collisions in my CSS. I do still have a small base set of styles that are shared but it's small enough to be easily manageable.

3- dynamic properties? CSS variables. Not an option? Child classes that apply the dynamic styles serve most use cases. Truly dynamic styles are rare, in my experience.

I'm still keeping an open mind about the possibilities, but my strong opinion (weakly held) is that I still don't see CSS-in-JS as more of a bandaid for people that like CSS and (for many, not all) those that don't have an in-depth understanding of it.


That's also what we do here on a dozen of apps and it works.

Each component has its own folder with its own css file and each rule starts with .name-of-the-component.

For dynamic properties, we either create conditional classes (e.g. 'success', 'error') or pass the rules through 'style' (e.g. dynamic height).

For dynamic themes, we create an object at the root of the app

  const theme = { header: { backgroundColor: black }, button: { backgroundColor: black }, ... }
Then pass it down to the related components

  <header className="default-header" style={theme && theme.header}>
  <button className="default-button" style={theme && theme.button}>
That being said, I tried styled-components once and don't really have negatives about it. It's a viable option.


All three of the points raised are just dismissing the root of the problem and offering a "solution" using plain CSS classes that relies on everybody following some bespoke convention to work around the problem rather than addressing it head-on like CSS-in-JS solutions do.

1. and 2. attempt to address the lack of modularity in CSS through convention when you can have guaranteed modularity through auto-generated CSS classes that are content-addressed and thereby globally unique by definition with CSS-in-JS. Not to mention you can use a real module system for sharing styles instead of being limited to sharing variables through some global context, which again opens up the possibility of name clashes.

3. recommends a solution for dynamic styles based on yet another CSS feature that relies on global namespacing, and then a fallback based on string concatenation that can't actually address all dynamic use cases. Then it goes on to dismiss the use case entirely, when in a single page application, all styles are inherently dynamic based on the state of the components that are currently being rendered, which is why there's such a painfully obvious impedance mismatch when implementing anything that's truly dynamic using CSS classes, when you have to resort again to concatenating lists of static classes together rather than mapping state to styles directly like you could with CSS-in-JS.

Of course, I'm not saying those approaches can't work at all, nobody is saying that. You can obviously make them work, and people have used those approaches for ages before CSS-in-JS came along. But using the existence of those approaches to dismiss a different approach that tangibly addresses the inherent flaws of those approaches doesn't feel like a particularly compelling argument.


Yes, it's dismissing the root of the problem because I am not convinced the "cost of doing CSS" is enough to justify moving to something like CSS-in-JS. Again, as I said above - it's a strong opinion, but weakly held - given enough evidence, I'd reconsider my position.

My point with the examples I gave was just to show that it's possible to handle the issues the author wrote about. I'd prefer to see efforts to fix the issues in CSS instead of discarding it completely in favor of a JS solution.

I'm not saying I can specify how to "solve" CSS issue in a couple paragraphs. As regards #3, that's specific to the kinds of dynamic styles I find most often in web apps. Very rarely do I see styles generated dynamically where it isn't effectively a choice between a couple of options (in my experience, of course). And when you do, you can just write out styles from the JS into the template (and I've definitely done fully dynamic styles in that way when it is necessary). Dynamic styles would be a place where I could see a fit for CSS-in-JS, btw.

The global namespacing this is something I believe is being worked on in the CSS Modules specification, but again, that is really easily solved. I can say loading external libraries can mess that up (i.e. Bootstrap and the ilk).

I don't care what people use, I'm glad the argument is what the author (who co-wrote the styled components lib) was what he liked. But I am really concerned that some proponents promote their way as the only way forward. Personally, I haven't found a situation yet where CSS-in-JS would materially benefit the application over a careful, convention-based approach. And I want to make sure people know there are other options that work.


I agree with you. I've done both approaches at scaled, and I'm still not really sold on CSS-IN-JS. Of course, I think it's a matter a taste (and maybe experience?) so to each its own.

Personally I much prefer using separate css (or sass) file, one for each component (assuming you also have a "layout" component for shared styles) and import each relevant css file as a module.

This way you keep writing our CSS out of your JS, but still can keep it scoped to your component. It's also obvious what css a component uses, and each to grep for when you want to delete some css.


There is this video about inline styles https://www.youtube.com/watch?v=k3OF4A30jSQ, based on a lot of real-world experience.

It addresses some of these points at 35:23 - that you can kind of make CSS work if you always do everything right, but it's not as easy in practice (most of the experience stuff is at the beginning - which shows that they did kinda do everything "right").


> Delete the widget? Delete the file.

This rarely happens. I would argue that creating an automated system to enforce "rules" should be favored over forcing every developer to know the rules and abides by them.

It is much easier to understand the relationship between css and js when the css is just a js variable.

Having built many large applications using the CSS file method, css modules, each widget gets its own file, co-locating css files with the js, I much prefer using `styled-components`. It provides a ton of flexibility, it opens doors for dynamic css by leveraging js (the hacks I've seen, had to write to get css dynamic is astounding), and I don't have to look very far to see how it's being used because the CSS is literally attached to the component I'm using. All I do in VSCode is cmd+click and bam, I can see the CSS for this component. There's no need for naming convention, there's no worry about global css variables getting into your styles, and there's no digging around looking for css that might be influencing your component. The best part for me is: when I delete the component, the CSS is gone as well. There's no thought put into scouring the FS to find lingering CSS that used to be used.

I love `styled-components` and most of the designers I work with also enjoy it.


Why wouldn't the CSS file be deleted? It should be co-located with the widget, so you just delete the entire widget folder.


Yeah, it's really not hard to delete a CSS file. People really are that lazy, but that's on them, not the technology.


Nobody thinks it's hard to delete a file.

It's hard to know when you can delete a rule. Are you positive that all the rules in your component's CSS file only affect that component? Then great, delete the whole file.

What about the individual rules within that file? How do you know whether your app is still rendering any components with the `fancy` modifier anymore? Keep in mind any JS on the page could be be dynamically toggling the `fancy` class, including in very rare circumstances, including from dynamic data that might bring the string "fancy" with it so that you can't just grep your codebase for it. Is it safe to delete the `fancy` rule?

Another problem is that even BEM admits that sometimes nested selectors are necessary. It's right there in the BEM FAQ: "While in general BEM recommends avoiding nested selectors, in this case they are reasonable."

Sometimes you need your button to look a certain way when it's inside a nav menu item.

So what's the solution? Either a nested selector (targeting both the nav item and the button) or a new modifier on your button, like `is-in-nav-item`.

Eventually your app changes and you're not rendering any buttons in nav items anymore. Maybe nav items don't even exist anymore and you at least remembered to delete those. Are you also going to remember all the places in your code you need to track down to delete these obsolete nested selectors/modifiers? Or is there just going to be dead code now?

What if the selector is slightly more general, and you're not sure if it's targeting other things as well? Are you confident that you won't break anything else? CSS selectors are effectively global. Anything could be secretly relying on the styles that a selector applies.

That is the problem. Not deleting a file. Your individual component CSS files are now the "append-only" stylesheets, not necessarily the whole combined stylesheet.


This is where something like CSS Modules comes into its own. You can have (nearly) absolute confidence that what's in the CSS file colocated with the component is only used by that component. Sure, there are escape hatches like `:global(...)`, but those should be considered a code smell.

The beauty of CSS modules over a convention-based approach like BEM is that you end up with cleaner, simpler CSS files -- with selectors like `.Widget .search.error` rather than `.Widget__search--error`. The downside is that there's a compilation step, but chances are that you already have _some_ sort of compilation going on -- even if just to bundle things up.

The way to handle "special" cases for buttons -- like when they appear in certain contexts -- is to allow the calling code to add a class to the button; a class which comes from the caller's own CSS module. Alternatively, use CSS variables:

Button.css

  .Button {
    background: var(--btn-background, turquoise);
    color: var(--btn-foreground, octarine);
  }

Nav.css

  .Nav {
    --btn-background: fuchsia;
    --btn-foreground: lime;
  }


> Are you positive that all the rules in your component's CSS file only affect that component?

Absolutely


This is a losing argument.

Judge all you want, but you can only change technology, not human nature.

Good engineering is to find pragmatic solutions that work in the real world.


You would like Vue's Single File Components, where HTML, JS, and CSS are all in one file. It's great.


In case anyone else was wondering what BEM is:

http://getbem.com/


How is it better to have only one of something and give it a class that nothing else uses than to use IDs how they're intended?


I take issue with your assertion about how IDs "are intended". I think that idea (and CSS being taught that way) is one of the reasons people have trouble with CSS.

There are quite a few reasons for preferring to not use IDs, here's two:

1- specificity of IDs always trumping things

2- having to change it from an ID to a class later on if it becomes a reusable item (which in a widget, is almost always the case). There is no reason a class cannot apply to just a single item, where an ID is by its nature limited.


> using something like SCSS > adopt a simple naming structure

and suddenly

> I still don't see CSS-in-JS as more of a bandaid for people that like CSS

Why are SCSS or poor-man's-substitute-for-modularity in the form of naming conventions fine, and why JS-in-CSS is bad?


Because one is an extension of the underlying technology, and the other one changes the technology out altogether. I still believe CSS is a vital part of the web ecosystem, and we should work to fix the underlying issues rather than just try to work around it via JS.


The underlying technology is the same, only the interface has been changed out(CSS files for JS).


> 2- Specificity issues? Never use IDs, stop using tag names and simple classes and adopt a simple naming structure

I have one exception to that in my own work, which is to only ever use IDs for styles that affect the layout of a block/component on a specific page. This makes sense since parts of a page layout are usually very specific and not that dynamic(in which case class names might be more appropriate). At the same time, component-level styles should never make assumptions about how they are positioned on a given page.

Let's say that we have a page `/blog/:entry_id`, and this page has a right-hand column to list related blog entries. This component would have an id `#blog-entry__entries-list`, which would control how the related-entries list appears on the blog-entry page(in this case, putting it in a column on the right), and a `.entries-list` class that controls the global appearance of the component.

This way, the entries-list can be used in different contexts without having weirdness caused by a margin working fine on one page but having to be negated on another page where the margin doesn't work. Try to add styles, but do as minimal overriding as possible.

In combination with BEM, primarily for the benefit of all selectors having the same specificity, I've found this separation of concerns between IDs and class names to be very powerful and simple to understand, especially since it doesn't require more verbosity.

Another part of my styling workflow is Sass mixins.

Let's say that we want the entries-list component to appear more compact on another page. Perhaps it appears somewhere on the site index, and takes up a little more room than we'd like.

Since component styles can't assume anything about their environment, and since layout styles(i.e. our ID selectors) can't know about the inner workings of their components, there needs to be a way for layouts to have a choice of component variations.

In this case, I would create a mixin `entries-list--compact` inside the entries-list Sass file, which would contain CSS properties that would make the entries-list smaller.

Back on in the index Sass file, I would include that mixin:

```

  #index__entries-list {

    @include entries-list--compact;

  }
```

But what if we only need the list to be compact at a specific page width?

```

  @media (max-width: 640px){

    #index__entries-list {

      @include entries-list--compact;

    }

  }
```

I've found this pattern of mixins to be very powerful. Any page can decide whether to use any mixin at any page-width. CSS for layout stays very lean, as the only properties it's concerned with 99% of the time is width, height, margin, and padding. A component can be completely replaced with new styles and behave properly on existing pages so long as it conforms to its existing "API" of mixins.


That's an interesting use case for IDs. I'll have to keep that in mind.


We built a relatively large social media management platform, and for one of our major features (a streams page that shows social media activities from different sources), we put a lot of our css in JS including all the logic for stream sizing/resizing and page responsiveness. I can honestly say that this approach is terrible. It is a maintenance nightmare. Even the smallest changes require a ton of time. We're now rebuilding the page from the ground up because it has gotten so messy, no one on the team is interested in touching it.


Why can't we see more of these stories surfacing on the internet. All I see when I search for CSS-in-JS on google is how, CSS-in-JS is so great.

Why don't we have more : "We tried it, it is the worst, especially for products which lifespan is more than two months"


> Why don't we have more : "We tried it, it is the worst, especially for products which lifespan is more than two months"

Because that last sentence is just rubbish, CSS in JS is great. I'm using it for large projects already 4 years. If your experience is bad you must be doing something wrong. CSS in JS is almost the same as working with (S)CSS, except for extra power to control dynamic elements without having to juggle with classnames.


Clearly when somebody has a bad experience, they are just doing it wrong.

Or perhaps there's something to it, and the idea is not as good as one might claim it to be.


Or they are solving other problems and that's the reason why one believes a solution is bad and another one thinks it's the best.


Juggling pre-compiled gpu stuff (css classes) exists for a reason.

Scss is like css.

Jss is css + unnecessary abstraction on top of css + unnecessary memory and cpu cycles + writing part of css rules inside flow control (which can turn into js in css in js.

GPU facing languages have always been ugly and not just in this industry. But they are like that because of their nature. Making them friendlier is always welcome, but replacing them with cpu stuff defeats the whole purpose of a gpu.


> CSS in JS is almost the same as working with (S)CSS, except for extra power to control dynamic elements without having to juggle with classnames.

I completely disagree.

Time and effort creating frontend design systems, will result in a set of CSS files .. but will also enable efficiency, flexibility, accessibility, maintainability and extensibility. These qualities just aren't going to be as available if you use CSS in JS.


There's nothing expressly better about SCSS over CSS in JS that you have demonstrated.

CSS In JS is mostly using similar structure, but often the JS dom interface naming... so fontFamily instead of font-family. It's also far easier to introduce codified variant functions or variable injection in JS than it is in SCSS.

I'm not saying don't use SCSS if it fits your model better... I've been very happy using react-jss via material-ui ... I've extended the baseline theme and that gets used throughout the application with each component defining its' styles that get injected.

Sharing can be a little more awkward, but it's easy enough, just call the same style method(s), or extend the baseline theme that gets injected.

The only thing you mention that might be better with (S)CSS directly would be efficiency and even that's relative. You can absolutely do all the rest with CSS in JS.


There have been many philosophical (and practical) conversations over the years that have lead to the development of a rich and varied frontend development ecosystem.

If you're building a frontend system, you need to consider the overall (macro) view, as well as the detail oriented (micro) view.

It's very difficult to do this with CSS in JS because of the compromises that need to be made to work in this way.


At my company, I made the executive decision to drop CSS-in-JS because none of those libraries support PostCSS, and most have their own from-stratch, half-baked CSS transformation pipeline, not 10% as powerful as the PostCSS ecosystem.

I love PostCSS, and I'll happily consider CSS-in-JS again when somebody writes a library that doesn't try to reinvent the wheel.


Poorly designed code is possible with any language. Was it unmaintainable because of something fundamental to css in js?


I am curious, what made it a maintenance nightmare?


Why did small changes require a ton of time?


... especially web designers.


What are you trying to say?


I'm unconvinced.

For one thing, it's not CSS in Javascript... there's no cascade and no sheet, so it's just "styles in Javascript". (And, actually, this article is only about a specific implementation.)

The benefits listed are:

- "confidence" - but I think that's a matter of understanding and mastering the tool, whether it's CSS or this library. As the co-creator of "styled-components" the author is no doubt a master of it. For for the general developer, perhaps a roughly equal effort would provide a similar level of mastery in each. So why not invest in the standard?

"Painless Maintenance" - I would have to use it deeply before I could say too much about this. But I would guess that the danger of creating spaghetti code and a spaghetti of .css are pretty much the same and have the same root causes.

"Enhanced Teamwork" - I don't see the connection here. The discussion in this section seems to be about mastery of the tools again. The team can learn how to manage styles though CSS-based techniques or they can learn through techniques based on coding Javascript and the capabilities of this library.

Not that CSS doesn't have its issues. IMO, it's too low-level to use directly for many cases. There are two main problems: (1) missing the tools to manage complexity, like scoping, variables, and modules. (2) allows you a lot of freedom to do bad things. But there are libraries that address these that don't throw out the fundamental design of CSS, as styles-in-code does.

To me it seems like a better approach to build on CSS to address its weaknesses rather than throw it out.

The design of CSS itself came out the recognition that the tight coupling of style and content has drawbacks, and this is signing back up for those drawbacks. And you better neatly divide your presentation code from your business logic code and data access code or you'll get all that coupled tightly as well.

I'm not dismissing this out-of-hand -- I haven't dug into styles-in-code approach so I don't have a deep understanding of it.

But I'm not convinced it's worth the time to look more closely at it. Really, not even close.


> "Painless Maintenance" - I would have to use it deeply before I could say too much about this. But I would guess that the danger of creating spaghetti code and a spaghetti of .css are pretty much the same and have the same root causes.

But as you pointed out, there is no cascade and no sheet. The styles apparently just apply to the stuff they are near in the code. No twisted logic to unwind, hence no spaghetti.

The potential problem I could see is that changes which would have been easy with a cascade would require lots of changes to copypasta in this approach. Like, "take the spinach out of this ravioli and replace it with mushrooms." Everything is scoped properly and the task is obvious at a glance-- it's just annoying.


> But as you pointed out, there is no cascade and no sheet. The styles apparently just apply to the stuff they are near in the code. No twisted logic to unwind, hence no spaghetti.

Ah, well, things are not that simple.

In a project of any complexity at all, the style of any individual element is typically dependent on a number of things which collectively make up the context of its presentation. E.g, the site theme, the component, and the individual element (at least -- usually there's an app-subsection and components are usually grouped into modules, etc.).

Note that this is inherent to the problem space and is true whether you're specifying styles in code or styles in cascading style sheets or any other way.

CSS provides a basic mechanism for dealing with this -- the cascade (though as I mentioned, IMO it is lacking some necessary features). Styles in code needs an answer as well.

If you were to simply hard-code styles at the element-level (which you can do using either mechanism BTW though its probably easier with style-in-code), you'll have a hard time finding all the places in the code you need to update if you want to make a change. You'll be doing a lot of full code searches, reading code, and trying to put yourself into the mind of the person who wrote the code in the first place.

The "spaghetti" in the metaphor are the lines of dependencies. We have spaghetti code when those lines are disorganized, entangled with irrelevancies, obscured, and otherwise unnecessarily difficult to deal with.

In fact, if you hard-code a style on an element that is dependent on the site theme, app section, component module, and component, you'd be hiding those dependencies, which creates spaghetti code rather than avoids it.

Now, I expect most developers would naturally try to avoid doing something like that. I'm just trying to point out why style-in-code doesn't really help you avoid spaghetti code.


Copying and pasting code multiple times creates spaghetti code.

Why does copying CSS multiple times (once for each component) not also create spaghetti code?

Many elements share style in a normal webpage. Font, for example. Having to specify the font in every file seems crazily redundant.

And if you separate that out into a separate file that gets included in many places, you lose all the other benefits like "painless maintenance".


In my opinion this is a workaround for a language flaw in the React concept.

Look at this beauty for comparison: https://vuejs.org/v2/guide/single-file-components.html


Hm, I don't share your opinion on this matter, to be honest. You can easily avoid this in both Angular (which does it out of the box) and React by including CSS Modules (https://github.com/css-modules/css-modules) which, if you use create-react-app to build your projects, is a 5 minute change to your architecture. So there really is no reason to write that down as a con for React.


I have so many small components that I would loathe to have a separate stylesheet. Yes, it's a small thing to just switch tabs, but this is a small problem. And these small problems add up and can be a huge pain. I really really like the SFCs in vue and compare it to a bit of butter on toast. It might be a small thing, but it seems like it makes a big difference.


So you can just use styled-components as in the OP


You can avoid many things by forcing yourself to use this and this practice. In my experience not all developers out there know what is "good" and what is "bad" practice and there are certainly many React developers out there who never heard about CSS modules. Let's say better it's not a flaw in React but a trap which can cause huge maintenance headache in my opinion.


Works out of the box for the most recent version of CRA, as well.


You're right, but community support around a certain pattern often makes it the de-facto practice, so defaults matter even for a non-opinionated library (where "defaults" are essentially what tutorials and thought leaders point to)


I always thought css-modules is the de-facto practice


I know a ton of companies who did not even heard the memo about it.


What you linked is "CSS-in-JS" (in the sense that the library/framework you use transforms the output for you, for convenience, i.e., you're not writing BEM or whatever - same as in the original article). Vue scopes the styles by adding a data attribute.

https://vue-loader.vuejs.org/guide/scoped-css.html#scoped-cs...

Inspect the result here: https://codesandbox.io/s/3v0pjzoy7q


To me this seems really implicit and magical and strange.

Where is template getting assigned to the code inside the script tag?

Does OtherComponent somehow mysteriously map to other-component? How does one pass arguments to it? Is a .vue file actually HTML or is it parsed somehow to be HTML?

The thing I like about React is the explicitness of it. This is a source code file that exports component X. Component X uses style Y as defined above because it's explicitly passed in as a prop, etc etc.


> a language flaw in the React concept.

What language are you talking about? React is Javascript

> Look at this beauty for comparison

Meanwhile Vue is neither HTML [1], nor strictly speaking CSS [1], and has a very wierd concept of how objects work in JS.

[1] It's a templating system with its own rules and mini-DSLs that ends up being compiled into JS.


> Meanwhile Vue is neither HTML [1], nor strictly speaking CSS [1], and has a very wierd concept of how objects work in JS.

Vue Templates are a very thin DSL on top of HTML. It's just markup.

Once you understand that, everything falls into place.


AFAIK you can't have non valid CSS in the style tag of a SFC, so, strictly speaking, it is CSS.


> and has a very wierd concept of how objects work in JS.

What is so weird about it? I personally find Vue vastly more approachable than React is, especially once you have to start writing all the plumbing to get all the libraries you need to go along with it to write a real world app.

> ] It's a templating system with its own rules and mini-DSLs that ends up being compiled into JS.

Vue has the option to use Webpack to compile html compliant templates to JS functions just like JSX (which BTW is not JavaScript and not HTML compliant and is also a separate concept that needs to be learned as well.)

CSS is just another add-on through Webpack when using Single File Components. Nothing really ground breaking here except for the fact that it creates a nice separation of concerns. This is especially true on teams with junior devs or designers. Or with a team that works on a site with mixed MPA and SPA features.


> What is so weird about it?

I go a bit in depth here: https://news.ycombinator.com/item?id=17471199

> Vue has the option to use Webpack to compile html compliant templates to JS functions just like JSX

Vue's templates are not HTML-compliant. They are just that: templates. That get compiled to JS anyway.

> JSX (which BTW is not JavaScript and not HTML compliant and is also a separate concept that needs to be learned as well.)

JSX is a very thin DSL on top of Javascript. It's just function calls: https://reactjs.org/docs/react-without-jsx.html

Once you understand that, everything falls into place.

> CSS is just another add-on through Webpack when using Single File Components.

It's not a webpack add-on. It's a part of Vue's templating engine that is essentially CSS-in-JS, they just give you a template to work in.


> It's not a webpack add-on. It's a part of Vue's templating engine that is essentially CSS-in-JS, they just give you a template to work in.

It's regular CSS in the templates and regular CSS in the frontend. There's no JS involved anywhere, unless you count the tooling, but we already use JS tools for CSS processing (PostCSS).

Scoped CSS is an old HTML5 feature that was dropped in favor of style encapsulation using Shadow DOM/Web Components.


I thought one of the beauty of vue template is 'It is not complete set of JavaScript logics, only subset that just able to support proper html structure.'.

It means you can't abuse JavaScript everywhere, creating totally unreadable render function, nest array mapping in Ternary operator and reduce it to what the hell no one can read and destroy all the readabilities.

For me, for you, for everyone, if you using that syntax, then it is simply readable just like html.

Less powerful, but the management definitly worth more.


> I thought one of the beauty of vue template is 'It is not complete set of JavaScript logics, only subset that just able to support proper html structure.'.

The problem with all templating systems is that they start with "we need to limit the amount of logic". But all templating systems find out that this is extremely limiting. So they grow. And grow. And grow. And grow.

Same with Vue. The amount of special cases and custom things just grows and grows. See my comment here: https://news.ycombinator.com/item?id=19199423

You need simple conditional logic. So you end up with v-if and v-else. Then you have to add v-if-else.

You need loops. So you end up with a custom DSL for v-for. And then you expand it to also work on objects. And you need to bind to object produced inside the for loop. And...

And you need to handle events. But events are anything but simple. You need to prevent them, you need to stop or start propagation, you need access to their properties. So you end up with v-on:click.stop.prevent. And function calls. And magic variables in the form of $event.

Worse still, all your existing knowledge about how to apply these concepts in JS is void. Template has taken over.

So in the end you end up with a system that is not really HTML, not really JS, but a weird combination of the two. And the amount of concepts is not exactly more readable than plain React that just uses JS everywhere.


Yes, that is the beauty. And when you really do need the full power of render functions Vue has those too.

https://vuejs.org/v2/guide/render-function.html


> I go a bit in depth here: https://news.ycombinator.com/item?id=17471199

I've read this before. Vue is a framework. It also has a templating system that is not JavaScript, it's valid HTML with attributes that tell Vue how to bind to it. It's really not that difficult.

> Vue's templates are not HTML-compliant. They are just that: templates. That get compiled to JS anyway.

Sorry, but you're wrong here. They are valid HTML.

https://vuejs.org/v2/guide/syntax.html

"Vue.js uses an HTML-based template syntax that allows you to declaratively bind the rendered DOM to the underlying Vue instance’s data. All Vue.js templates are valid HTML that can be parsed by spec-compliant browsers and HTML parsers."

> JSX is a very thin DSL on top of Javascript. It's just function calls: https://reactjs.org/docs/react-without-jsx.html

IMHO only the simplest of components featuring JSX that don't read like a spaghetti PHP coding nightmare to me. For the small number of times you actually need the full power of JavaScript you could also use JSX in Vue with a render function if necessary. I personally prefer to keep my templates and logic separate when possible.

> It's not a webpack add-on. It's a part of Vue's templating engine that is essentially CSS-in-JS, they just give you a template to work in.

No, it's not part of the template engine, it's part of vue-loader which is used by Webpack to create single file components.

https://github.com/vuejs/vue-loader


> it's valid HTML with attributes that tell Vue how to bind to it. It's really not that difficult.

You mean it has at least three JS-like DSLs (which are not JS, and have different rules depending on which context they are in). In addition it has a very weird binding system which I described at length in the linked comment.

Yup. "Not that difficult".

Meanwhile JSX is a single consistent DSL that directly maps to function calls:

   <Tag prop=(string or valid Javascript expression)>
      other tags, strings, or valid Javascript expressions
   </Tag>
That's it. Even "html-like" attributes that people seem to not like... are exactly what HTML attributes are in actual Javascript DOM APIs [1] [2]

The amount of custom attributes, custom DSLs and gotchas just in the "HTML" part of Vue is staggering in comparison: https://pbs.twimg.com/media/DbVEoKOX0AEEen6?format=jpg&name=...

And funnily enough it ends up being compiled to what React is in the first place (here's the output of a Hello World app in Vue):

    var render = function() {
      var _vm = this
      var _h = _vm.$createElement
      var _c = _vm._self._c || _h
      return _c(
        "div",
        { attrs: { id: "app" } },
        [
          _c("img", {
            attrs: { alt: "Vue logo", src: require("./assets/logo.png") }
          }),
          _c("HelloWorld", { attrs: { msg: "Welcome to Your Vue.js App" } })
        ],
        1
      )
    }
Look, it's exactly what React without JSX is [3]. Only in React you don't need to invent a custom scripting language and binding rules.

[1] https://developer.mozilla.org/en-US/docs/Web/API/Element/att...

[2] And I'm really sad to see React team seriously discuss caving in to mob and considering replacing className with class etc.

[3] https://reactjs.org/docs/react-without-jsx.html


> That's it. Even "html-like" attributes that people seem to not like... are exactly what HTML attributes are in actual Javascript DOM APIs [1] [2]

The attributes / DOM properties in JSX are also a mixed bag and not consistent. See https://github.com/facebook/react/issues/13525#issuecomment-...

> Look, it's exactly what React without JSX is [3]. Only in React you don't need to invent a custom scripting language and binding rules.

JSX is a custom extension to JavaScript. It's not part of JavaScript or intended to be part of the spec or implemented in browsers. In fact, you have to use some sort of transpiler in order to use it. So, it's not just JavaScript.

> https://pbs.twimg.com/media/DbVEoKOX0AEEen6?format=jpg&name=....

There's really nothing that complicated in here, if you're familiar with Vue. In fact, it's really easy for me to see what's going on at a glance in one place, which is my personal preference. From my own experience, that's rarely the case when working with React the way JSX tends to get broken up because it doesn't have something as simple as a standard if conditional statement within JSX itself.

I've never claimed you do not need to learn anything when working with Vue templates, you need to understand how the system works, but it took me all of a few hours to understand. The features and benefits that I prefer over React/JSX make that worth it to me.


> JSX is a custom extension to JavaScript. > In fact, you have to use some sort of transpiler in order to use it. So, it's not just JavaScript.

Yes. However, one thing you fail to see is that it directly compiles to function calls.

   <Tag a="b" x={y+z}>{valid JS expression}</Tag>
is

   React.createElement(Tag, { a: "b", x: y + z }, [<valid JS expression>])
Which means:

- you have access to JS variable in scope

- you can use JS facilities (proper if/switch statements, for loops, functional programming, you name it)

- you need no additional scripting or templating features. It's, well, just Javascript.

However in Vue (emphasis mine):

> There's really nothing that complicated in here, if you're familiar with Vue.

Yes. Exactly. If you're familiar with Vue

So:

- custom tag attributes: v-bind, v-if, v-for, v-on, v-show, v-model... (I honestly don't know how long this list is)

- custom attribute shorthands: :key, @key

- attribute extensions: v-on:keypress.prevent

Inside attributes you can have:

- Javascript expressions (much like React inside {})

- or magic binding:

    v-bind:href="url", v-if="seen" etc.
- or JS-object-like magic bindings which resolve to a string:

    v-bind:class="{ active: isActive, 'text-danger': hasError }"
- or JS-array-like magic binding that gets resolved to a string:

    v-bind:class="[activeClass, errorClass]"
- or a magic array with objects that gets resolved to a string:

    v-bind:class="[{ active: isActive }, errorClass]"
- or a separate DSL for v-for:

    v-for="(item, index) in items"
- or a separate DSL for v-for where you can bind entities from the DSL (which looks exactly like the magic binding to data from the component, what happens when they clash?):

    v-for="(item, index) in items" :key="items.id"

- or JS expressions that may be function references that may be things that look like function calls but actually aren't:

    v-on:click="counter += 1"

    v-on:click="greet"

    v-on:click="say('what')"
- with special magic variables

    v-on:click="warn('Form cannot be submitted yet.', $event)"
- with special magic modifiers

    v-on:click.stop.prevent="doThat"

"It's not that difficult" ©™ And the list above doesn't include the overview of the JS code that underlies components in view. It's another whirlwind of magic and non-magic: https://news.ycombinator.com/item?id=17471199

Oh yes, and this gets compiled down to some JS that bears little to no resemblance to original code.

And somehow people complain about how React is difficult. Wat?


> Yes. However, one thing you fail to see is that it directly compiles to function calls.

I understand how JSX works, stop patronizing me. The only thing I fail at is seeing how any of your examples are complicated or have magic so deep that you need to continue to burn Vue at the stake for. In fact, I find your Vue template examples completely intuitive and easy understand with minimal time invested in learning how Vue templates work. It's my preference to spend a little bit of effort up front learning how Vue templates work in order to have clearer separation between business logic and templates.


> JSX is a very thin DSL on top of Javascript.

With its own syntax. Which looks like HTML but isn't.


Considering the differences lean towards the DOM interface names for given attributes and properties, I wouldn't exactly call it NOT JS.

It's actually an XML abstraction that closely resembles HTML + JS-DOM, and is then converted into function calls and arguments.

It's also about as close to E4X as an abstraction that I've seen and something I wish was cross browser over a decade ago when it was first introduced by Mozilla and Adobe, but that's a long side-track. In the end, it's very effective and works well imho. Yes there are some more complexity points in some places, but I don't think anything else does it better. Vue imho is comparible, but I don't like it as much and I feel that Angular is far worse in practice.


Yup, that's what you can have with precompiled templates. Riot.js introduced the same concept of scoped css years ago, I wish it was more popular. On the other hand it goes against the "it's just javascript" concept of React.


Vue's single file components are incredible. They're so great for the developer experience, which is Vue's entire ethos.

Add in Tailwind utility classes and you've got a great design system that can be built on the fly with consistent standards.


Be very aware that most popular CSS-in-JS libraries (such as JSS) will completely break CSP (Content Security Policy). The default reaction is usually "Just allow unsafe-inline in your CSP header", but this is dangerous advise as it will disable CSP! I've even seen 'experts' advising to use webpack to set a static value as a CSP nonce during build-time...

If you want to use CSS-in-JS, you'll either have to use server-side rendering to inject CSP nonces in your index.htm [0], or set up a complex build system to extract the CSS from your JS so you can serve them as .css files.

Using server-side rendering to inject nonces into your single-page client side rendered webpage is such an ugly hack. I'd prefer the second solution but I have not been able to find a solution like that, nor do I have the time to dive into the webpack rabbit-hole to do so.

[0] https://github.com/cssinjs/jss/blob/master/docs/csp.md


The down-side with this is very high coupling between UI logic and style.

If style becomes out of fashion, you have to modify files that contain logic. If framework (react/vue) becomes out of fashion, keeping styles will be difficult.

The other down-side is thousands of web developers having to re-learn CSS and the tooling behind your app instead of just changing CSS files.


Your styles are coupled to your UI logic anyway, even if you go out of your way to make them implicit by separating the CSS and JS into their own files. It's better to have the relationship explicitly defined in code instead of hiding it. That's the whole reason why CSS sometimes breaks in unexpected ways: you fail to realize the implicit coupling of the styles and the UI logic, so you fail to reason what changes need to be made both to styles and the UI logic to make your change.


In practice, I think a lot of people have found that you can rarely do a complete overhaul of a website’s design using only CSS. Even if you could, it would be impossible to feel confident that your changes look reasonable across all uses of said CSS. So if you’re doing a big redesign you will usually have to work with logic anyway.

I think there’s truth to your second point though - reusing styles in parts of a project that does not use the same framework. Something like Tailwind CSS can be a good option then.


> you can rarely do a complete overhaul of a website’s design using only CSS

Full design yes, but branding/theming is much easier if you use an external styling framework like Bootstrap 4 or Foundation and use their component and utility classnames.

We have a 300+ page app and tried the one stylesheet per component thing with theme and layout all combined in the past, and was a huge mistake.

Banning most custom CSS in place of using the Bootstrap component and util classes has been so much easier.


Ok, but, the average startup web dev stays at a company for like two years? And then the thing eventually gets rewritten anyway in the latest flavor of the week, because nobody is using the same tools as two years ago.

I guess the concern for longevity most devs have is amusing when most software, if its not like systems level stuff, or problems most devs dont want to solve, tends to get disposed pretty frequently.

By the way, most of the software that actually sticks around was written in C and generally solves a problem most people wont tackle. Like zlib or sqlite or nginx or the linux kernel. You can almost pretty much judge the longevity of a piece of software based on how hard the problem it tackles is. Like encryption or compression? Those libraries are going to be around forever, because how many coders do you know that can write a semi compitent encryption library? And how manu coders can write a templating engine?

Like most of web dev is throwaway code. It just is. Arguments based on like "will they be able to restyle it in 10 years?" Well are they even going to be around?


> encryption or compression

both of these are pretty bad examples, as several modern developments have surfaced in both cases - here are 2 examples

- https://wikipedia.org/wiki/Curve25519 - https://github.com/google/brotli


I agree, but it is not really an excuse to write bad code.


Absolutely. But im not sure "bad code" is the same thing as code written for a purpose at a particular time. I think something can be good code if its lifespan is understood in the context of the business goals. I just get cynical when I hear people apply these principles to something that may live five years. Not every project is going to be maintained for 30 years


If you're building a complex UI that uses components as a cohesive library, there will always be some coupling. Even with the classic bootstrap example, once you've built an application and introduced any number of third party components, it gets messy to change things.

Better to have a cohesive set of theme/rules and get them to work together as best possible. I've been a big fan of material-ui and react-jss and is imho about the best option I've used in over two decades of working on web based applications.


You don't need to use different languages to decouple things. A common pattern in React is to decouple logic and style using presentational components and container components (there are lots of articles on it if you Google those two terms), and I find that split to be much more natural than trying to split up HTML, JS, and CSS (which often need to cooperate with each other). One good practice with CSS-in-JS is to only use CSS in presentational components.


>If style becomes out of fashion, you have to modify files that contain logic.

So just put the styles in separate .js files and import them.


And now you know why "dark mode" is touted as a feature, instead of being a 5 line css file with some "!important" rules.


CSS... sweet memories. For some reason I never was able to learn how the damn thing works. I worked for Google Analitics in 2011 and we rebuilt it using new in house built framework which championed an idea of a separate styles for an on screen component. Every dev was starting a new component with: clean_styles directive as nobody was brave enough to deal with what comes from the top. Even though it was possible to use cascading part, nobody was brave enough to own styles for the whole product. So, We ended up with so many styles we had to split them in couple files as we reached a limit in IE on number of styles in one file. Last time I checked GA is loading 3 of them... Is it a time for some other way of doing it?


> I never was able to learn how the damn thing works

People not taking the time to learn is not a reason to throw an entire building block of the web out.

(Yes, I realize there are a lot of people who know CSS and still choose CSS-in-JS, but I'm specifically referencing the point re: not learning CSS.)


I didn’t say I did not spend time, I said - could not. Same applies for most people in the team. I think we had coupe folks who were spending a lot of their time explaining CSS.

My theory is that CSS was something that was treated as a task. Make a lot of client/server side development and then make these freaking lines align perfectly. So, most of time engineers were avoiding styles, applying them was the most tedious and hated part of the job.

And it is hard to be good at something you hate.


I agree with you re: the task comment, there is a difference between JavaScript developers and Front End UI developers. It's almost like the full stack discussion but just in the front end ecosystem.


They significantly overlap, so wouldn't say they are different. I would suggest that most "JavaScript developers" in the box you'd put them in are backend developers that only know a minimal amount of JS and don't really know JS well and by extension the browser itself.


And these are the same types who take on JS tasks without really knowing JS (or the DOM), writing what is often layers of garbage JS with extensions, addons and jQuery in what could have been 5-10 lines of JS.

I don't claim to be an expert on the DOM, and I might be close to expert in JS itself... there's something to be said for knowing at least enough to know what is possible and what to look for BEFORE working around a problem and introducing a bunch of crap.

I am one of those that knows CSS well enough and still chooses JSS, as imho it's easier to coordinate a set of theme values and configuration across a project. IMHO react-jss and material-ui do things VERY right in terms of what works for not only components, but a larger project.


I write CSS in CSS and my JavaScript in JavaScript because at some point abstractions pile up into this massive cognitive burden for anyone adopting your code, especially when they didn't follow the exact same path as you technology-wise or if they're newcomers. I want my work to be pick-up-and-play, not RTFM x 20 abstractions and tools.


Even if there was more cognitive burden, it's insignificant compared to the drastically reduced amount of context switches the developer has to deal with.


While Styled Components, Styled JSX or Linaria (which doesn't require a JS runtime for production) are nice solutions, the fact that I can no longer use the colour picker and other tools to live edit CSS from the styles pane in the Elements tab in Chrome Dev Tools, sometimes makes me want to go back to plain CSS to get this functionality back.


You can! I do this all the time.


With copy and paste? :)


Am I misinterpreting something? In my app that uses CSS-in-JS, if I go to the "Elements" tab of my browser developer tools and select an element, I have the option to inspect, add, remove and change styles — including using the color picker and bézier curve editor — and have it reflected live on the page.


There's a little known feature in Chrome where you can save your inspector changes locally:

https://rafaltomal.com/tips/save-css-chrome-inspector/


When my styled-components app is in prod, the styles are non-editable. When developing, I can use Chrome Dev Tools. On prod, I have to copy paste. Maybe I'm doing something wrong?


I believe this is a result of it using the "CSSOM" browser APIs for speed in production. Unfortunately, browsers apparently haven't figured out how to make such styles editable yet.

It's definitely a limitation of certain CSS-in-JS implementations, but unfortunately one that inherently comes from "using the platform."


Why is it that whenever anyone posts anything about React, there's a horde of Vue users trying to convince us that they are doing it better? It feels a bit desperate.

The great thing about React is it is purely JS (or JSX, which is effectively a macro for the underlying JS). Which means it is explicit, and predictable. Perhaps that means there's less sugar, but any sugar and magic comes at a price.

I'm going to have a look at Vue more anyway, out of curiosity, though.

Edit: I note that some of the anger at React has been "Why does it need Redux/MobX if it is so good?". But Vue has Vuex to solve the same problem?


CSS in JS is one place where Vue has a substantially better experience. Being able to toss scoped-css, written as normal in a css block is what I call nailing the developer experience. It is all the best parts of css in js with none of the downsides.


You can do this with styled-components in react too.

https://www.styled-components.com/


Yea, but this isn't out of the box. This is some 3rd party solution for a pretty major part of an application.


I understand your preference for frameworks, but I actually appreciate that it's not out of the box.

I'd rather have libraries focus on one thing and do it well - the Unix philosophy. This lets me compose the appropriate libraries for the problem at hand.


You are complaining about react's philosophy itself, which is they don't want to make any choices for you.


Angular also does this, fwiw. Also allows you to manipulate the styles from DevTools which I hear is a problem in CSS-in-JS


dev tools works fine with both react and Vue if you set it up well, meaning to extract css to a file instead of throw it inline. Most setups extract to a file


I got to web development pretty late (circa 2015) so my perspective may be skewed but CSS in JS seems much more natural to me than separating markup from style and then linking them up later with global class names.

It reminds me of when I was in college learning C where all of your code is just dumped into one namespace, and then later learning Python (or basically any other modern language) with actual modules and namespaces. After seeing it done that way it just makes no sense that it would ever be done the old way again.


In recent projects I tried 3 new approaches: React's CSS-in-JS, Vue's Scoped CSS and Tachyons/Tailwind Atomic CSS.

All of those solutions were a huge improvement and scaled better than any of the previous pure-CSS techniques I was using before.

BUT the key here is that those things only work when you rely on React/Vue/etc components. If you have have to rely on copy/pasting markup, things go wrong FAST and you lose track of your app style and things get duplicated. You also to have to enforce SMALL components. If you duplicate markup between components things get hard (but not as nasty as if you weren't using components).

I honestly believe that people not using modern frameworks can't see the advantages of any of those techniques, and would urge everyone to try them out in component-based project.


Those techniques work well for design systems. CSS in JS on its own, and Vue's Scoped CSS are a different thing than Tachyons, Tailwind or Styled System. Styled System is for CSS in JS what Tachyons is for CSS, you're using a design system, either the default values that are already present, or your own customizations.

This basically frees you from making style decisions while coding, depending on your design system, things will just work well together as you create your components, with spacing, colors etc. all being already figured out.

This means that you don't "translate" pixel perfect designs, you use design tools like Sketch or Figma to find the rules and scales that you then translate into the style sheet/design system.

Instead of doing the "configuration" in your CSS when you're coding, you basically have an intermediate step where you set up those rules in advance, and can just focus on composition.


> Those techniques work well for design systems.

That's true! I find that enforcing a consistent and quickly-changing design system is way easier than when I was using old techniques.

> Instead of doing the "configuration" in your CSS when you're coding, you basically have an intermediate step where you set up those rules in advance, and can just focus on composition itself.

You summed it up perfectly


Way to defeat the purpose of CSS. How is hard-coding the styles to each element something better? How can this not lead to MB of worthless crap to download, instead of the content?

Want to show a title? Use `<h1>`, and style it with `h1 {color:palevioletred;font-size:18px;}`. Except hardcoding the font-size as pixels is another code smell, the `h1` is already bigger than the text body. Use `2em` if you really need things to stand out.

It's in the name, Cascading.


Thought experiment: imagine doing React development with all inline styles. Someone invents CSS. Would you use it?

Of course not: CSS is a bad idea in 2019. In 2004 it solved some of the problems we have React to solve today, but much, much weaker


How do you handle advanced CSS Level 3/4 selectors, CSS grid, and media queries?


The idea with CSS-in-JS is that you don't use selectors. Since you are constructing DOM nodes individually, you don't need to select them. Styled components can accept props, which lets you style dynamically (e.g., using an array index to replace `:nth-child`).

With regard to media queries, it depends on the library. For the library the author is using, the media queries are defined inline: https://www.styled-components.com/docs/advanced#media-templa...


Does it use (shared) variables, like with SASS?

With SASS, I find it really convenient to define variables for common/brand colours, for example.


You can define a "theme" object, which you can inject into your styles (with an expression inside the template literal). Other libraries support variables more directly.


What's the problem, you just use them. If you need to reference component itself you can use & selector, works exactly like sass or less. If you want to reference another styled component you import it and ${Component} will reference autogenerated class. Also nobody stops you from writing nested css rules. You can also write cool media query helpers like this https://www.styled-components.com/docs/advanced#media-templa...


Yeah or pseudo elements / hover / focus etc?


People often confuse the two, but CSS-in-JS is a distinct concept from "inline styles" (which can make pseudo selectors more challenging).

Almost all CSS-in-JS solutions (including styled-components mentioned in the article) still support pseudo selectors, media queries, etc.


I'm always surprised to find no mention of React Native in discussions around CSS in JavaScript.

They've got it figured out. Stick your styles at the bottom of your component. Vertical flexbox by default. And... that's about it. It just works beyond that point.

We liked it so much we ported our webapp from react to react-native-web. It's an amazing library. You can freely mix in regular react, but the styling story is so good with react-native-web that you'd never want to. It powers mobile.twitter.com and the author (same person who made normalize.css) recently joined Facebook, which hopefully means more development to come.

You'd have to pay me to go back to styling the web with css. It really is a hair-pulling experience.


What I don't like about css-in-js is how it makes things really hard (or even impossible) for endusers who may want to use an extension like stylus or tampermonkey to modify the site styling or behaviour.


Author here, happy to respond to any questions. AMA!


Honestly, I think the CSS-in-JS approach is not for me and we haven't used it except for times where there was no other way to do something.

Instead we have used CSS Modules (https://github.com/css-modules/css-modules), first by including it manually in webpack, now it's already built into create-react-app so I just have to install node-sass and call my Sass files ComponentName.module.scss and I can use them the same way in my .tsx/.jsx files that you use CSS-in-JS. IMO that's a lot less messy and makes your jsx files smaller and better to read. Also it's easier to write Sass and have the pros of that language on top.

Did you consider this approach at all and what did you not like about it?


While different from Styled Components, many people still consider CSS Modules to be squarely in the realm of CSS-in-JS. It literally generates a JavaScript module that you must import into another JavaScript module in order to actually use the CSS classes you write, after all.

Having some experience with CSS Modules myself, I thought they were interesting and definitely an improvement, but still left a lot to be desired.

For example: needing to use a helper like `classnames` to join/toggle many dynamic classes together was very ugly and cumbersome. There is also no way to "directly" tie variable state/props to CSS rules – you're still required to use this indirection where a state/prop relies on there being a predefined class/modifier in the CSS file.

e.g.

    font-size: ${props => props.size}px;
    color: ${props => props.special ? 'red' : 'blue'};
With solutions closer to the "fully JS" end of the spectrum like Styled Components, there are no extra "modifier" CSS selectors to come up with to handle the above situation.


Bonus point: you get hot reload while editing CSS.


Honestly, it sounds like you now have a write-only site, as you will have a hell of a time 5 years down the road when the CI changes.

Personally, I find the Vue.js concept much nicer, but even given that, I define my styling in LESS (SASS...) to benefit from inheritance/mixins on the level of styling. Semantic approaches like BEM or Bulma make a lot more sense to me.

It seems to me React has made a feature out of a flaw, much like the intermingling of code and HTML back in the days with ASP/JSP/PHP.


BEM is just a weird hand-cobbled way to add scoping to CSS


- Were there moments when you cried back SASS or vanilla CSS?

- In your react example, I see you created <Title> as styled.h1, but that's an awkward way of bootstrapping a component. Even if I used SC, I would still put the style information outside my component code in the same directory. At this point I don't see the benefit over doing something like:

    import * from './login.scss';
What can SC do that regular CSS or SASS can't?


The big win for me is if you're making an SPA, all the knowledge of the app state is already stored in JS (redux, or local state, or handed down as props if using React). So instead of toggling styles on a class, you just hand the state to the styled component, since it's just a function that returns css.


Toggling styles is a good question. I have sometimes multiple classes that have to work together. For example to open a panel, I use some translate/transform, different positioning. How do you compose different styles for a single component?

How do you deal with mobile, where sometimes I have to override dozens of declarations with media queries?


- No! I have not missed class name collisions and specificity wars at all, and I have enjoyed being able to dynamically adapt my styling as necessary.

- This ties into a broader point of having "style components" like <Grid /> and <Row />, which is a very nice way of working in React. styled-components (the library) simply takes that pattern and enforces it across your application. See style-components.com for links to some more resources about this pattern!


Your reasons sound similar to those given for standardizing on in-line styles as much as possible. Both methods are ways to subvert or work around the cascade. I would like to hear from you why you think the cascade works the way it does, and what aspects should be preserved so as to not 'throw the baby out with the bathwater' while adopting these new methods. Thank you!


How do you plan to accommodate NoScript users?


NoScript users are almost always economically irrelevant to the business posting the page. They tend to be extra aggressive blockers of ads (and therefore ad revenue) and are sufficiently far from the center of the bell curve technologically that they are both a tiny minority and their product needs and wants tend to be edge cases that are not economically efficient for the business to pursue. I get why NoScript users want to run NoScript, but it's the most powerful signal a web visitor can provide a business to say "focus your resources on the needs of others ahead of mine."


The only reason I know of to bother supporting NoScript users is so that when you announce your site on Hacker News you don't have to read that one angry privacy guy talking about how bloated your site is because it requires 200 KB of JS.


I know this will be unpopular, but after a certain point, noscript users just get a bad experience and that can't be helped. If a developer wants to provide a rich experience, then there will always be certain platform requirements. Without them, you will have a lacklustre experience. It's like saying "I want to have all the whizzy functionality of your app, but I want to access it using a standard, run of the mill, mud-laden potato" - it's just not going to be possible.


noscript users certainly signed up for a subpar internet experience, but its not just them that should be thought about.

Slow internet connections are a reason to think about the experience when loading JS is slow and/or failed. It's not just 'poor people' who have slow internet - 'rich people' on inflight wifi or on the internet on the train can result in things not loading.


There isn't much that can make an in-flight connection seem quick, but we've tried with our PWA (https://usebx.com/app) and to a certain extent, succeeded.

Ok, we do assume that you have visited our webpage at least once in an area of strong signal, however, once you've done that, all the JS is cached and all we transmit back and forth are lightweight, gzipped json payloads, often less than a kilobyte.

I use my own PWA regularly, and found it actually quite usable in-flight.


I think this is a big issue with such JavaScript and load heavy web-sites & apps. They forget that they have users without 1GB connections and who can't afford, weather financially or location based, the download the 500MBs of data required to load their web-site. That and hiding CSS inside of JS feels like a sneaky tactic to keep people from editing it? Or does it actually create the CSS on the fly? I wasn't quite sure after reading the article.


No regular JS only website/app required 500mb of data. Please stop exaggerating. It does not make your point valid.


I know how the sausage is made, so I know that making a full web app work without JS isn't at reach for most teams/products.

By knowing how the sausage is made, I'm also aware that the line marking the aforementioned certain point is often drawn too early, at informational (i.e. document) stuff where HTML and CSS are fully capable on their own.


You underestimate developers; they can make it work without JS if they have to. But why should we constrain ourselves?! I mean, there is nothing wrong with JS when used properly.

In fact, JS is extremely useful in the browser. It adds to the richness and interactivity of webpages. We must collectively appreciate this, and stop denying this! Even HN is a better experience with JS.

Some sites do give JS a bad name, and poorly used JS is something I hate too, but JS as a concept is something that I wholeheartedly support. Thankfully, the web is mostly opt-in - if you don't like the way a site employs technology, just don't visit it. Simple.


During server-side rendering CSS-in-JS returns a <style> tag with all the CSS inlined.

If you do not server-side render, it does not matter whether you put your CSS into JavaScript or not—your JavaScript app is not going to render anything anyway.


They're economically irrelevant so they're ignored. Their demands tend to be edge cases.

NoScript users are like the customer that demands the most but pays least. After some rants of such customer, they're ignored.


React apps have to be deliberately engineered to work without JS at all, via server rendering. Assuming that's done though, the CSS in JS can just be server rendered too.

It's rather easy too if you're using a (great) library like styled components - this functionality is built in and just works with a couple of extra lines of code.

The deeper question here is will the app work at all without JS. That's quite hard to achieve (every client side interaction must have a server rendered equivalent accessible via a url or url params, essentially) but the CSS part is easy.


Does he need to? I know my users don't use NoScript.


It doesn't really matter how the JS components are styled if NoScript users aren't loading JS, though I assume you know that and are just trying to make a point that sites shouldn't be using JavaScript.


You generate a css file with something like webpack.


Why do you think CSS-in-JS has only caught on in the React community?


Probably because it's the only one among major popular frameworks that doesn't use weird compile-to-js templates, and relies on JS only.

Others (I'm thinking Angular and Vue) have their own templating systems that they compile to JS anyway.


Herd mentality.

RDD (resume driven development).

Cargo culting.

Ooooh shiney!

"I'm not confident enough to make my own decisions, so I'll let the 'community' decide for me."


Can you say how this affects the classes and ids you add? I'm guessing you use classes and IDs a lot less because you don't need things to match the css against?


I wonder what impact CSS-in-JS has on rendering performance and code size.

I bet that browsers are very efficient at parsing and applying CSS directives to elements. Parsing and executing the JS and additional DOM manipulations could have a massive negative impact on performance, at least intuitively. Does anybody know of a performance benchmark that compares CSS-in-JS to regular CSS?


If you make sure your site works without javascript as well(unless it's actually an app) it's fine by me.


This is a requirement that most sites can simply dismiss these days. The distinction between an app and a website is blurry, a lot of interaction simply works far better with Javascript.

Supporting "no Javascript" can be costly. It's possible with server-side React and careful engineering, but why bother? What's the impact on the business?


I don't know what the real impact is, but if your site shows me blank page without javascript(I have it off by default) I am closing the tab.

I don't think supporting noscript version is costly because for me that's how it supposed to be by default. 90% sites that are currently on the internet would work just fine without any js and 95% would work with as little as hackernews has. Modern CSS allows to create most of the experiences and unless you need some interactive forms or serving live broadcasts, games etc., there's just no point in using javascript.

Over the years I've stripped javascript from about 40sites which I visit daily without sacrificing any real functionality. Those sites download and render visibly faster, only relevant cotent is shown and I even implemented dark theme for them. My only javascript fixes are for broken galleries or embedded videos (and those wouldn't even be necessary if developers wrote a fallback to noscript).

It used to be that developers loaded many little scripts so I could only block the useless crap but since everything is minifed and bundled in one huge unreadable file, I just use uMatrix to block it entirely and Stylus and Tampermonkey to fix it.


> I don't know what the real impact is, but if your site shows me blank page without javascript(I have it off by default) I am closing the tab.

I can show you "this site requires Javascript" instead, but let's just say you're not part of the target audience and that's fine.

> I don't think supporting noscript version is costly because for me that's how it supposed to be by default.

That highly depends on the site, of course.

> 90% sites that are currently on the internet would work just fine without any js and 95% would work with as little as hackernews has.

99.9% of websites are not actually businesses that employ developers. If that's your standard, I agree. A simple webpage does not require Javascript.


Bother for human rights. "Javascript" is costly too - but maybe not your concern since it's not a business cost.


> Bother for human rights.

Which human right, specifically? Humans have the "right" to install a modern browser and enable Javascript.

> "Javascript" is costly too - but maybe not your concern since it's not a business cost.

Indeed, the cost you pay to run Javascript does not show up in my budget, just like I don't pay your ISP to serve my site to you.


I've been doing almost the opposite - enhancing and extending valid CSS stylesheets by using JavaScript to define new features and functionality to be made accessible and usable by writing valid CSS.

An overview of my tooling and workflow is here: https://github.com/tomhodgins/caffeinated-style-sheets

The big idea being that CSS should be able to apply to _any_ HTML, no matter how it was created before it got to the browser. Many style-related tools integrate tightly into your framework or into one particular workflow but don't give you the flexibility you need to apply any styles to any website unless it happened to be put together with specific tools a specific way, but I don't think that provides enough flexibility.


I've been using elm-css on a project lately. Pretty cool with typesafe CSS. Also inline, but since everything is functions it's easy to compose/reuse as well when needed. (Compared to the string templating shown in this article)


So reading this article made me have a bit of an epiphany: What is being described isn't CSS-in-JS. Instead, this is style properties in JS.

This is the equivalent of inline styles. We don't call it "inline CSS" because it isn't CSS. Nothing cascades with inline styles, just as they don't with "CSS-in-JS". And you don't have to worry about specificity with either implementation.

In other words - all the things that make CSS the powerful language it is are stripped away to just a listing of arbitrary properties.

So, CSS-in-JS, do yourself a favor and stop calling it that, because what you are coding is nothing even remotely close to CSS.


As someone coming from a traditional strict separation-of-content-and-style background and now convert to Styled Components, CSS-in-JS felt unnatural to me when I first encountered it. The problems with styles in large applications are well known and I had a solid handle on them with BEM and other bits of tooling, namespacing styles to a particular React component to avoid collisions etc.

It took me helping my brother learn how to do web development to shake me out of that mindset. He's not from a traditional webdev background and he got quite far quite fast with React. When he showed me his code, I noticed he was inlining all of his styles in his relatively small React components. I was going to explain why its bad practice to do that, but when you're building small almost atomic components, that approach actually makes a lot of sense, its what the BEM methodology tries to do albeit in a poorer way. CSS-in-JS tools like Styled Components preserve the spirit of this approach and minimise the downsides.

I think CSS-in-JS lends itself quite nicely to atomic design. At my current company, one of the first things we did was build a component library of atoms & molecules that are shared across many applications, keeping our design language very consistent.

We also make heavy use of Styled Components' theming capabilities, so we wrap our React apps with a ThemeProvider and give it an object with theme variables that drive the look and feel of our components. This is super useful when you have to support whitelabeling like we do, but even if you don't, its nice to keep your mystery-meat colors and spacings all in one place similar to how you might with SASS.

One of the gripes a lot of people have with CSS-in-JS is portability, and while that is a drawback, I feel it's an anti-pattern to rely on shared CSS styles to enforce design consistency across many deployables. It's kind of a classic case of developers trying to solve a process issue with technology, which is admirable, but from experience styles go out-of-sync with eachother quite easily and its rare that you can drop a CSS file into another project and have styles just work without having to do rework, so the benefits of sharing CSS rather than writing new styles off a styleguide are marginal at best. Again, this is all my subjective experience, your mileage may vary.

We still have a couple of issues with Styled Components, no technology is perfect and SC is still relatively young, but so far the pros have far outweighed the cons to the point where none of us really feel the itch to go back to SASS or plain CSS. I'm definitively not a magpie developer by any stretch, I'm usually resistant to change for the sake of change, but CSS-in-JS makes a lot of sense when you use it how its intended


I'm of the opinion that CSS actually has more in common with logic-based programming languages (like Prolog, or more specifically ones based on defeasible logic) than with ordinary languages of the "imperative" or "functional" sort. I think that reading CSS with this in mind helps make sense of some of CSS's features (e.g. specificity, the way selectors work).


Story of my life as a front end developer... you can invent an abstraction to make life easier and simultaneously increase code size and complexity more than 10 fold. Easy is often an anti-thesis of simple.

Basic front end code isn't that challenging, but it does take some actual practice (not half-ass practice followed by a million poorly considered short-cuts).


What about non-basic front end code?


Well I did spend this weekend trying figure out how to dynamically update keyframe rules with JavaScript only to discover the window.CSSKeyframesRule API is incomplete on most browsers so I found a different nonstandard way to solve that problem cross browser. I have not seen a failure to implement standards like that in many years.

Just about everything else on the frontend is absolutely solid cross browser with 5+ years of thoroughly tested support. People don’t write abstractions to fix weak technology, they do it to fix weak developers.


No.


The problem with orphan CSS is adressed very intuitively in Vue.js with single file components (HTML + JavaScript + CSS).

https://vuejs.org/v2/guide/single-file-components.html


Off topic, but I really like the new site design, particularly the Appearances page!


I really appreciate you taking the time to comment on that! I put a ton of work into the design, so you saying that makes me feel really great.

Thank you!


Agreed - love the Web Mentions addition!


> Why I Write CSS in JavaScript

tl;dr because it's convenient.

It's also redundant, goes completely against the features of CSS (the cascading part), doesn't utilize the possibility of selectors, children, etc, ugly, and computationally heavy.

But yeah, why not.


Not to mention that it doesn't work without JavaScript enabled on the client (unless he's generating CSS in server-side JavaScript). That's fine for a true web app (and web apps do have their place), but it's completely not fine for a web page, which should display just fine without JavaScript.

People should not be forced to grant you permission to execute code in order to read text & view images.


Hi, I'm from the orthodoxy and I'm here to disparage you.

$disparaging_paragraph

Thank you


Every time when some language generator become more popular, it's a sign, that something is wrong with the main language. It happened to Java, JavaScript, CSS.


"Deprecate CSS, disregard design" seems to be the standard practice for engineers silo'd off from designers, and the business-at-large.


Nothing in Javascript makes me not afraid, the less i have to touch it, the better i feel.

SASS + BEM accomplish the result in a more manageable way.


Why I don't write CSS in JavaScript:

people disable it


CSS === Cascading Style Sheets

In the context describe in the article, there is nothing cascading, and there are no sheets.

What he / she is doing is going back to the late 90's and inlining all the style'ing. I'm not judging the technique, simply pointing out that it's not actually CSS.


styled-components is not popular on HN it seems. Allow me to share my own positive experience:

I have built websites in a variety of different ways, with a variety of different CSS schemes. I've worked with SASS, LESS, BEM, every major css framework, in both SPA and SSR environments.

I have also built react SPAs with the above variety of CSS schemes, as well as CSS-in-JS libraries like Aphrodite and Styled Components.

I currently build and maintain a medium-to-large web app with a small team, right now ~200 components, 31k lines of js including test files.

Styled Components has been an immensely positive experience for us, and i would not want to use any other way I have mentioned, or has been mentioned in this thread, to manage our styles in our app.

The reason why is because of the simple fact that it allows us to think of our styles just like any other component. We do not need a separate way of managing styles that we need to keep track of, whether a style is used is 100% the same as whether a component is used or not, which makes eliminating dead code, dead styles, easily managed through tooling.

It allows us to define simple, semantically-named components like <FlexGrid/> and <BigButton/>, and allows us to compose these components together to build up styles just like any other react component.

Styles are easily overridden from their parents. We use Ant Design for our UI toolkit, which does not use Styled Components, but any styles we want to override, as well as styles in nested classes, are easily done by wrapping an antd component. All the parent component needs to do is accept a "className" property. This makes interop with other components simple.

Effectively what this means is that after awhile, we get to live in a world where I can add a component into any given part of application, and be very certain its going to look and behave the same way it does in every other part of the application. When I'm building new features I don't want to think about styles, except when adding styles is part of the feature itself. Styled Components is the only way so far I've found that does that sufficently.

Globally-available CSS is great for web pages, but not so much for widget-based GUI web apps, which creates leaky abstractions. Most ways of managing CSS are systems to get around that, or treat it as a feature.

In short, 10/10 would use again, even over other CSS-in-JS libraries like Aphrodite. Note this opinion is scoped purely to react apps. Vue's approach seems appealing as well but I have not used it before, but to be honest I do prefer being able to have everything in JS or JSX, but thats a different discussion.


I hated styled-components when I had to use it. It introduces a ton of unnecessary nesting and weird abstractions just to give devs something that is superficially similar to something they are familiar with. I keep it simple with styles in JS.


This stuff irritates me. Imagine if you read an article titled "why I listen to audio books". Nobody cares. Do whatever works for you.


I feel like a lot of this boils down to a variation on Greenspun's Tenth Rule: "Any JavaScript-centric web development framework contains an ad-hoc, informally-specified, bug-ridden, slow implementation of half of a web browser."

"I can add, change and delete CSS without any unexpected consequences. My changes to the styling of a component will not affect anything else. If I delete a component, I delete its CSS too."

This is readily achievable with ordinary CSS. Selectors by ID/class have existed for multiple decades. A Ctrl-F for said ID/class name should be pretty painless to do even in the case where you're doing everything in one giant spreadsheet (though in this day and age of CSS preprocessors, no reason why you couldn't have widget.js and widget.css, the latter of which gets compiled into the final spreadsheet as part of the build process).

"Never go on a hunt for CSS affecting your components ever again."

I'd hardly call Ctrl-F a "hunt". JavaScript can't fix bad code hygiene/organization.

"I cannot expect all team members, particularly juniors, to have an encyclopedic understanding of CSS."

So you expect them to have an encyclopedic understanding of your CSS-in-JS library instead, then?

Or perhaps it'd me more reasonable to be okay with looking things up every once in awhile?

"With CSS-in-JS, we automatically sidestep common CSS frustrations such as class name collisions and specificity wars."

I'm curious how much these are actually problems in the first place (or at least problems inherent in CSS itself), and how a CSS-in-JS framework expects to solve them without completely reinventing the browser's styling engine.

"This leads to a marginally slower time to interactive, but a much quicker first meaningful paint!"

If you didn't try to do everything with a giant blob of JS, you wouldn't have to do these kinds of ridiculous tricks to reduce time-to-first-paint.

"Send only the critical CSS to the user for a rapid first paint."

If the CSS is not critical, then it shouldn't be sent at all. No reason a backend framework couldn't selectively send only the CSS relevant to the HTML being sent.

"Simply style your components with a global theme or based on different states."

<foo class="widget primary"></foo> <foo class="widget secondary"></foo>

So difficult.

"CSS-in-JS combines all these benefits into one handy package and enforces them."

Yes, at the cost of needlessly reinventing stylesheets and making it significantly more difficult to modify the styles downstream (e.g. for accessibility reasons).

"Thousands of companies use CSS-in-JS in production [...] (including this website)"

As an experiment, I switched JS off for that page and refreshed. The styling certainly doesn't seem to be happening client-side. Instead, the HTML source contains a bunch of obfuscatedly-classed divs and a giant obfuscated stylesheet in an inline <style> tag.

Surely JS is not specifically needed to achieve this result. This could've been done with CSS-in-Python or CSS-in-Ruby or CSS-in-C or CSS-in-Lisp or CSS-in-COBOL or CSS-in-Brainfuck or whatever. It also could've surely been done with a dedicated language-agnostic CSS preprocessor. Further, it could've been done the "hard" way (not really hard at all) with CSS selectors alone (since that is indeed the end result).


CSS was a mistake. Adding new features will not fix it. It needs to be scraped and rethought from scratch. There needs to be a something completely new to replace it, and it must be a full programming language.


This sounds like an awful idea.

Just put your CSS in a .css file where it can be cached, delivered by CDNs and can easily be edited in a single place.

Separation of content and presentation has been around for a good reason. One should always avoid mixing logic and design because it will break some day, no matter how well you think you handle it.


> Just put your CSS in a .css file where it can be cached, delivered by CDNs

.js files are cached and delivered by CDNs too.

> can easily be edited in a single place

If you change the name of a class (or add a new one, delete another one, edit the structure of the component, etc...), then you have to open and edit 2 files. With author's solution you don't. The CSS is collocated with the component.

> Separation of content and presentation has been around for a good reason. One should always avoid mixing logic and design

Author is talking about putting the React component (presentation) and its CSS (presentation) in the same file. He's not mixing business logic and design.


> .js files are cached and delivered by CDNs too.

Not in 2019, in the age of excessive A/B testing, where every page load gives you a different set of JS.


If you need caching then you would likely server render your page and that would inline all of the critical css to be cached as well.

Writing your css in JS files also does nothing to prevent you from separating content and presentation. You can write components that just handle styling. I see more problems with separation in css where you end up with one giant file that handles the whole site.




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

Search: