Hacker News new | past | comments | ask | show | jobs | submit login
React: CSS in JS (speakerdeck.com)
33 points by insin on Nov 8, 2014 | hide | past | favorite | 7 comments



At the last slide author says that the goal of that talk was to convince us to drop CSS and use JS.

Can't say that those slides were very convincing. Right now it looks way too overengineered.

I'm not a fan of muddying JS with bits of HTML in general, and now CSS in JS?

Yes, that may work for Facebook. They've been inventing their own way of doing things for a while now, but I very much hope that won't go beyond Facebook.


I agree. CSS is global, but that doesn't mean that it can't be managed. I think going down the road of having programmatically generated stylesheets is solving a relatively small problem with an extremely over-engineered solution. Soon enough, you can't actually develop without the use of dozens of different tools for generating source maps, transpiling, etc. In all honesty, any presentation that says "If I started with this, you would have written me off as crazy" is probably giving itself too much credit and is in fact based on crazy.

The whole "button in an overlay" section of the presentation shows just how mind-bending this becomes. In a sane universe, one simply needs to write `.overlay .button`. But of course, you can't do that with CSS that's referenceable from a single name (or where you're statically applying styles to an element rather than letting the CSS...well...cascade). I could see if the solution presented made me say "Oh, this is a much more intuitive way of styling a web application." It didn't. Instead, I read, "We have this crazy proprietary namespaced CSS system that has limitations that we can't work around without building an even crazier system on top of it," and thought to myself, "Well don't do that then."

So now you're at a point where everything is an inline style. Your browser's devtools are essentially useless because you can't see how the CSS cascades. What overrode what? God only knows, go look at the JavaScript.

Of the seven problems outlined at the beginning, I think few of them were really a problem to begin with. A codebase that 1. properly organizes its CSS into files with descriptive names and a sane directory structure 2. uses OOCSS or other best practices 3. is mindful of style bloat 4. has a sane DOM structure and 5. uses a preprocessor of some variety for variables does not suffer greatly from any one of those issues. I work on a codebase of >10^5 lines of CSS that minify+gzip down to 30kb. That's a single small JPEG worth of code.

I would be interested to see some of the alternative solutions that Facebook explored that don't dive straight into the Twilight Zone.


We organize our SASS files very carefully. One file per component, careful naming, strict rules about overriding a component's internal classes (".mycontainer .somecomponent .somecomponent_title" is illegal). It's still painful.

One reason is cascading. The way CSS applies to trees means that every component has to be aware of what properties it could accidentally inherit. So to code defensively, you override things like colors and fonts. Using SASS mixins helps.

But sometimes you do want contextual modifiers, for example styling all components differently when they're in a certain type of container. For example, if the container's background is light grey, we'll want all nested text to have a subtle bevel (ie., white text-shadow).

It's tempting to use cascading for this, but that breaks — by definition! — separation of concerns. In one way it's better to actually have each component be container-aware; for example, given that Form and SpecialContainer are both components you can do this in form.scss:

    .SpecialContainer {
      background: #f0f0f0;
    }

    .Form {
      .SpecialContainer & {
        text-shadow: 0 1px 0 #fff;
      }
    }
It's cheating, though; now you have a dependency between the Form and SpecialContainer that really wasn't needed. So when I'm not being lazy, I resort to explicit parameters:

    .Form {
      &[data-light-background="true"] {
        text-shadow: 0 1px 0 #fff;
      }
    }
Now I have to pass "lightBackground" as a prop to the component have it set the data-light-background attribute. Of course, this only works the component embedding Form actually knows that it has a light background or is embedded in one that has a light background. Not ideal.


You've missed the "not" word. I had to double take too.


Right. Missed that one, my bad.

Nevertheless, that was not the best presentation on some issue and it didn't help to explain that issue any better.


I can see that this approach might be viewed with a lot of suspicion, but this gels with a lot of problems we saw while building the MontageJS framework.

CSS is global, and it is a big problem to manage while building a large web app (which of course Facebook is). I think everyone building a large site or app has come across a bug where a CSS rule is unintentionally overriding another. They are a pain to track down and almost impossible to prevent.

I haven't played with this approach (as it was only talked about today!) but I think it's on the right track. The only thing I would like to see is the "CSS" put into its own module and required into the component JS file. Not only would this maintain the separation of style and markup, but also make it more approachable for those CSS experts coming from the current way of doing things.

I'm really looking forward to seeing how this progresses.


I'm not sure the implementation is quite what we need, but I definitely agree with the rationale.

CSS is global, as they point out, and CSS makes assumptions that may not be true today. For example, most apps these days — at least the kind I build – gain zero benefit from separating the style from the DOM. We never, ever apply different stylesheets to a single app.

The few use cases where truly separate stylesheets would be useful aren't significant enough to justify the separation. For example, "themes" are implemented through SASS variables that drive the presentation -- not with separate stylesheets.

And generally speaking, apps are simply too complicated to reimplement the entire app's stylesheet multiple times. And CSS cascading rules are sufficiently gnarly (eg., the exactness of the selector guides priority, except !important, etc.) to make things too error-prone to work in practice.

CSS was designed for basic marked-up hypertext documents, not today's sites or single-page apps. It works fine for documents, but for everything else it's increasingly showing an impedance mismatch, especially with respect to isolation and layout handling. Even with "flexbox" it's very limited compared to constraint solvers like Cassowary. We have to face the fact that layout belongs to content.

Anyway, there are a few problems with the CSS-JS approach:

- Media queries aren't possible anymore and must be done with JS. (I usually end up doing a lot of this in JS anyway, because media queries only deal with viewport sizes, not parent container sizes, so media queries break component isolation.)

- When you have styles applied to almost every element in a complex component, the DOM will look increasingly messy. You can't do mass-application things like "div > li { ... }".

- It's going to massively increase DOM size.

- Surely browsers must have highly optimzied CSS processors these days. I can't help but think that applying entire style rules to DOM elements must be slower than just referencing an existing compiled style.

Personally, I suspect a better way to approach this would be a React-specific, component-oriented style language. Not the modest tweaks they demonstrate in the first slides, but something built from the ground up.




Join us for AI Startup School this June 16-17 in San Francisco!

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

Search: