Skip to content

Instantly share code, notes, and snippets.

@joeybaker
Last active August 29, 2015 14:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joeybaker/fc72e5e2c43a98d46cce to your computer and use it in GitHub Desktop.
Save joeybaker/fc72e5e2c43a98d46cce to your computer and use it in GitHub Desktop.

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.

@ianobermiller
Copy link

Couple other points:

No Style Fallbacks

What you are really trying to solve is vendor prefixing, and you should be doing that before you construct an inline style object anyway. There are are lots of libraries to do lightweight prefixing in JS. Here is an example usage of cssVendor.

Re-usable animations with @Keyframes are out too
Sure, if you assume inline styles mean you can NEVER use CSS, but that doesn't have to be the case. With a simple helper, you can inject the keyframes into a style tag and use them in your inline styles.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment