A Journey toward better style
Acknowledgment
- I would like to thank Nathan Marks for the awesome work is has done addressing the styling issues.
- I would like to thank Pete Hunt for his inspiring talk on reusable components.
- I would like to thank the following oranizations for giving me the opportunity to share this topic:
- Paris.js
- ReactJS-Paris
Date
- 2016-10-27
- 2017-01-26
Online version
CSS-in-JS comparison
We started looking for the best styling solution available. Nathan Marks built a custom solution for the needs of Material-UI: stylishly. Ultimately we reverted. We think that it's much better to rely on the community. Still, that was a very valuable experimentation.
Regarding the community, looking at the MicheleBertoli's repository. You can tell that there is a lot a solution available.
What's the best one for our needs?
For the sake of this presentation, I have selected 5 libraries that I think have taken valuable tradeoffs. I'm gonna give my point of view in the rest of this section. The information given are biased by my understanding of the reality.
-
- Singularity: Extended CSS DSL. Generate style at built time.
- Motivation: Having some isolated and composable module of CSS. Stay as close as possible to the CSS ecosystem.
-
- Singularity: Per rule style usage and injection.
- Motivation: Khan Academy was looking for a better way to style components with an existing code base. E.g. usage of
!important
.
-
- Singularity: Uses post-CSS at runtime.
- Motivation: ? My best guess is, leveraging JS power while still using the CSS syntax.
-
- Singularity: Has a low-level API.
- Motivation: ? I have no clue. I should be asking @nathanmarks.
-
- Singularity: Has a functional API.
- Motivation: ? Could be inspired by posts like Functional Programming, CSS, and your sanity.
Interesting dimensions
We can't compare anything without some dimensions. But having too much of them add noise.
- The API.
- Is it taking full advantage of JavaScript? JavaScript is a much more powerful language than CSS. When using it, you no longer have to worry about CSS linter, CSS syntax, CSS pre-processor
- Is the API low or high level? The theming requirement is quite high for Material-UI. The much freedom we have, the better.
- Is the API declarative? The more declarative we are, the better.
- Time to first paint. We have a legacy of poor performance with our inline-style implementation (lack of caching). Reducing the delay between an interaction and something on the screen is quite critical for us. I have run a simple benchmark on a modified version of CSS-in-JS There is quite some factor than can make a difference. I have noticed a factor x2 of difference between the fastest solution (CSS modules) and the slowest one (styled-components).
- Is the style pre-processed at runtime of build time?
- Is the style injected as class names used or upfront during the bootstrap?
- How are the classNames generated? E.g. computing a hash of the rule object could be expensive.
- Library size.
Users of Material-UI could be using a single component out of the available ones.
E.g. the
<DatePicker />
. We want to minimize the entry price of using a single component. - Server Rendering. Server side rendering a page drastically improve perceived performance for a user first visit (for repetitive one, Service Worker are even more efficient). Material-UI can't be taken seriously without a strong answer to this point.
- Can requests be parallelized? I.e, not using a singleton, that's also bad for security.
- Is the API allowing streaming the response?
- Unbiased. The less coupled with a solution we are the better. We also want to make sure the solution we are going to use reach a broad audience. E.g. LESS is used by the Angular and React community. That's increasing odds of success.
- Are we coupled to React?
- Are we coupled to Webpack?
- Debug. Users of Material-UI were complaining that the debugging experience was poor with inline-style. Browser dev tool handles much better the CSS. Still, the styling solution can impact it.
- Are the classNames readable in dev mode?
- Are the classNames injected into a single
style
element or multiple? - CSS output size. That last dimension is less interesting. I was just curious.
Results
CSS modules | Aphrodite | styled-components | JSS | Fela | |
---|---|---|---|---|---|
API | -- | + | o | + | ++ |
Time to first paint | ++ | o | - | + | o |
Library size in kB | ~0 | 18 | 126 | 22 | 9 |
Server Rendering | + | o | - | ++ | o |
Unbiased | o | o | - | + | + |
Debug | - | o | o | + | - |
CSS output size | o | ++ | + | + | o |
++
awesome+
greato
enough-
not great--
no
Going forward
Material-UI has chosen JSS
. It's addressing our unique needs.
Your needs are most likely different. It could be better for you to use a another solution.
Be sure you make an informed choice 💡.
The compared libraries are going to improve. My comparison might not worth anything one year from now.