Skip to content
Peter Mouland edited this page Sep 24, 2016 · 2 revisions

Couldn't have website without CSS, so the choice is all about how to include that into the Universal App.

The problem with all solutions that involve components is what to do when the app is rendered on the server; how do we ensure that NodeJS knows what to do when it sees import styles from './styles.css.

The base app does include CSS, but not in a modular fashion, it is simply included as an asset within the html and has no connection to the code.

Options?

There are currently 2 very popular options, plus a third option which seems to get overlooked:

  • CSS Imports
  • CSS Modules
  • CSS in JS

CSS Imports

CSS Imports simply uses node-hook to ensure NodeJS ignores and Scss imports while trying to render on the server.

import from 'styles.css';

cont styledDiv = () => <div className='my-div' />

This method is most like how everyone else uses CSS in that the CSS is not changed. We must take care of not getting the class names wrong (probably via BEM or SMACCS) and we must make sure we apply those class names correctly.

CSS Modules

CSS Modules uses an extra query (modules) on the existing webpack loader. This modules query param will rename the classes being used locally to ensure they never clash. This means we can carry on using CSS as we always have done, and forget about having to manually scope the class names with things like BEM and SMACCS.

import * as styles from 'styles.css';

cont styledDiv = () => <div className={styles.myDiv} />

When a project or team is of a certain size, I can see how this can be very useful and easy to pick up.

CSS in JS

This method allows CSS to be skipped all together in favour of Javascript Objects containing key value pairs which react translates into styles. This means you can import the css.js like any js file and insert them straight into React.

import styles from 'styles.css.js';

cont styledDiv = () => <div style={styles.myDiv} />

This sounds almost too good, and in a few ways it is. To enable things that come out of the box with CSS (like :hover), you now need another plugin, like radium. Once you wrap the component in the Radium function it now understands how to deal with :hover keys in you JS CSS object.

It brings true isolation which means css scoping is not a problem. Globals are also easy and natural as its very easy to merge objects while applying the styles.

Once downside is the amount of html generated when applying the styles. Imagine a style being applied to a <li>. I also found that while AutoPrefixer helped me out, Radium want me to set up its config with a userAgent for the request object to ensure the server matched the client. This is simply not possible on servers that want to cache the html.

In my experience, having to rely on wrappers and converters to translate code for you always turns out bad. Did you have get board of waiting for that Grunt wrapper to update so you could use a new NodeJS module? In the end, people went back to just using the real thing. I think it will be a similar story with CSS in JS.

Conclusion

You can probably tell I wasn't a fan of the CSS in JS method. There were just too many work arounds needed and more tech to make things work. don't add to a problem to fix it, just remove the problem.

I will probably stick with CSS Imports (w/ BEM). It seems to produce the least code and has the least amount of learning needed to adopt it. However, once a project get large enough, or for distributed project, I can see how CSS Modules might be the winner.