Closed camjackson closed 7 years ago
Thanks for the thorough write-up. There are so many approaches to this and I think coming to a considered decision early will be awesome.
Here's a couple of things that come to mind for me:
So in summary, I lean towards anything that keeps the styles with the component and is easy to reason about.
The sign up app will be plain old css on a single stylesheet as it is easier for Rabble Rouser users to override it with their own styles.
As for the admin app, we still don't know but we're leaning towards the in-JS css given that it seems easier to maintain for us devs :)
Started using styled-components. Will keep working with it for now unless there are concerns.
This RFC is to look at our options for styling the UI, and to pick a preferred approach. As always, we don't need to set this in stone forever, but we do need to at least pick something for the immediate future.
I'm going to try to keep this mostly informational, and put my opinions in a separate comment. I'm sure that my biasses will creep in though, so please feel free to suggest any corrections or additions to this summary.
Global vs. other styling
Global styles
There are certain things that are a natural fit for a traditional stylesheet such as fonts, box-sizing, etc. These would probably go in a single, top-level stylesheet that effects the whole application. This stylesheet should be kept as small and simple as possible, and shouldn't need a preprocessor like SASS.
All other styling
Everything else is a bit more uncertain. Plain old CSS has well-known issues with its global-by-default nature, and can very quickly become difficult to maintain, because you don't know how many places any given selector is affecting. In addition, you often end up in a specificity battle, and it's not long before everything becomes
!important
.There are lots of approaches to solving this problem. Here is a decision tree that attempts to summarise the main choices to be made, and what solutions they might lead to (the options here are deliberately biassed towards what's in common use in the React ecosystem, seeing as that's what we're using):
Decision 1: Stylesheets or CSS-in-JS?
Keeping separate stylesheets might be more familiar to people who have worked with CSS in the past. On the other hand, it might not go far enough addressing some of the problems with CSS.
Some argue that mixing the styles in with the JavaScript is fundamentally wrong, as it violates the separation of concerns. Others would argue that splitting code up based on language is somewhat arbitrary - with React, the decision has already been made to define views (i.e. HTML) in JavaScript, so why not bring the styles in as well, and have all three encapsulated in one place for any given logical component?
CSS in JS may make it harder for e.g. designers who can write HTML & CSS (but not JS) to just work on the styles. Again though, that ship may have already sailed with the decision to use React.
Decision 1A: Assuming stylesheets - conventions or tooling?
If we are to keep writing stylesheets, then we'll definitely need to pick an approach that solves some of those specificity and global-ness problems.
Some claim that you don't need fancy tools and libraries to make CSS work - you just need to learn how to write good CSS. In that vein, specific methodologies/conventions exist in order to keep things neat. In the absence of any real experience with these, I'll just list some that I've heard of: OOCSS, BEM, SMACSS.
The counterpoint is that those conventions put the burden on developers to remember how things are meant to work, whereas a tool-based approach can put more constraints around how you work, making harder to forget/get it wrong. CSS Modules is an approach where stylesheets are split into import-able modules. The class names in each module get assigned a random suffix, so that
.button
in one module doesn't conflict with.button
in another module. You then import the relevant module into JavaScript and look up the class names from the imported object. This solves the scoping problem. (See the link above for examples.)Decision 1B: Assuming CSS-in-JS - inline styles or generated stylesheets?
The most obvious way to do CSS in JS is to just put everything in inline styles, e.g.
<div style={{color: 'red'}} />
. This works fine until you need to do something that inline styles don't support, such as pseudo-selectors or media queries. Radium is a library that solves this problem by tracking those states in JavaScript. I.e., if you put a:hover
in your inline styles, then Radium attaches listeners to theonmouseover
andonmouseout
events of that element, tracks the hover state, and activates your hover style accordingly. For the most part this works fairly well, though some (perhaps rightly) criticise the decision to reimplement in JavaScript, behaviour that browsers provide natively.The other approach to CSS-in-JS is to use some technique to generate a stylesheet from the JavaScript. Similar to CSS Modules, the scoping problem is then solved by randomising the class names, and looking them up from a JavaScript object.
Decision 1Bi: Assuming CSS-in-JS with generated stylesheets, which library?
At this point the decision seems to mostly be down to: which library's implementation is the best, and which library's API do we like the most?
After some research, the three most viable options seem to be:
Rather than inject my own analysis here, I'm just going to suggest having a look at the readme for each of the above libraries, in order to get your own feel for how the work. After that, this article is an interesting direct comparison of Aphrodite and JSS.
For completeness, one final link is this repo, which has a table comparing a whole bunch of CSS-in-JS libraries. If you see one that you think should be a contender, call it out!