React's Inline CSS
React encourages you to deal with CSS with inline styles. The advantages are numerous: but can be succinctly stated as: it ensures that components do not overwrite the styles of other components. That's a huge when working with a team of more than a few people.
As a fan of CSS (as completely flawed as it is), I was skeptical from the start, and I'm now sure that Reacts's approach is not ready. At a minimum it's not ready. More likely, it's fundamentally flawed. It’s no good at vendor prefixes, abstraction, media queries and performance.
I will say, once you get used to JSX, it's actually really nice be able to write styles in the same file. It feels like a real "component". But, there are far to many restrictions to make this practical.
No Style Fallbacks
There's no way to override a style on the same selector. This is impossible to do:
div {
display: -webkit-flex;
display: flex;
}
Because you can't declare two display
styles. That makes flexbox
impossible because iOS needs the webkit prefix. My workaround is to add a .flex
class to the global CSS and apply that classname in React, but that's a kludge, and gets away from "component" feel of React.
No Media Queries or Element Queries
Media queries are broken. You have to use JS to detect widths and update inline styles accordingly. I was initially excited by this, because it means that element queries are the default! But, if you go down that route, you'll have to use .offsetWidth
and window.resize
all over the place. That's crap for performance. All the global resize
event listeners will slow you down, and offsetWidth
is a good way to cause a recalc-style and kill performance.
If you opt for straight media queries (which is unfortunate because element queries are more component-style), then you need to use something like matchmedia (polyfill). This is a bit slower than the native code the browser can use to do these same calculations… but it's close enough, so at least performance isn't much affected.
No matter which approach you choose, if you render on the server (you should), you have no way of finding the window/element size. This means, the initial state you ship down to the client has a very good chance of being wrong and you loose a lot of the benefit of server-side rendering – your users are likely to experience a Flash of Incorrectly Styled Content (FISC). That's a major gotcha. With CSS, we're ensured that the stylesheets download before the HTML, so we never see this problem.
No Global Styles
The whole point of inline-styles is to prevent global styles – but sometimes, global styles are good. One of the first things I wanted to do was use normalize.css
. There's no way to that, you have to have a stylesheet. Things would be different if you could tie a stylesheet to a component. For example, you could have a component that only styles headings called type
. Then each time you use a heading, you require that type component, and your <h1>
just looks right.
Re-usable animations with @keyframes
are out too. That's a bummer because CSS-based animations are a lot easier to make performant than JavaScript based animations.
Performance
After all this, you're still stuck with the fundamental flaws that are inline styles: additional initial download times because of all the additional markup, and the ongoing performance hit as the the browser needs to parse all the style
tags instead of a single CSS rule. Inline styles are slower than a stylesheet.
Granted, all CSS performance is unlikely to be a large bottleneck. But this is a fundamental flaw of inline styles. It might be worth the trade-off but combined with the other limitations, I'm not sold.
What I'd Like to See
More markup and moving calculations from heavily optimized browser-internals to JavaScript is net performance loss. Without @keyframes
animations gets a lot harder. Without global styles we loose out on the cascading nature of CSS. Without stylesheet downloads, our pre-rendered HTML is subject to FISC . And, without style-fallbacks, we don't get wonderful features like flexbox.
But, all is not lost – much, if not all of these problems could be solved if we moved away from rendering CSS to inline styles and instead rendered them to a stylesheet! React already attaches a unique id to each component. It should be possible to grab on to that to abstract our styles, authored as inline, to a stylesheet.
Some thoughts off the top of my head.
Style fallbacks
Great point, and one I hadn't thought of.
No Global Styles or Media Queries
Why not combine approaches? Nothing says you can't drop in
normalize.css
. Or use media queries to structure your page. Ideally your components are pretty isolated from this or it makes them hard to share across projects / teams / companies.How do you guys solve that problem with atomify? If I want to use two components that depend on different global styles, there's not really a way to resolve that is there?
CSS animations have their own problems, and there are good reasons why you might want to control them in JS, but for simple UI flourishes.. yeah, that clearly belongs at the component level, and there isn't a good way to do that inline. I've seen wrapper components deal with the animation in JS, then you just wrap it around what you need as the method of re-use. I believe React Native does something like this, which gives a button (or view, or image) an animation in response to being touched.
In the worst case, you could re-implement something like browser animations in React. Not that I would advise doing such a thing.
Performance
I'd be curious to see how inline styles compress when gzipped, but your point remains. I don't think anyone has really benchmarked this.
Certainly! CSS is brilliant for layout (well, parts of it) and styling. It's used for much more than that though.
Is this a good use case for CSS: http://alistapart.com/article/quantity-queries-for-css ? Impressive hack, but not even close.
What about selectively hiding different panes of a dialog depending on which class is applied? No, that is pushing your application logic into your styling and mixing concerns, but I've seen it done a lot.
With the hover issue I mentioned in my tweet, you could make a good argument for solving it on either side.
What about
:before
and:after
? Is that part of "CSS: The Good Parts"? Or was it a workaround for not having components?This approach is already working in React Native with teams of devs. The concept, at least, is vetted, but there are realities about the browser environment that make it difficult.
I don't think they are insurmountable, but I agree I wouldn't start building a real product like this just yet.