I've just started using Material UI, and I know that it uses CSS in JS way of styling components.
I saw 2 methods in the documentation of how to create styles:
Using the sx
prop:
<Box sx={{ backgroundColor: 'green' }}/>
Using the makeStyles
method:
makeStyles({
root: {
backgroundColor: 'green'
}
})
I know that CSS in JS is much less performant than native CSS.
But between these 2 methods I just wrote, which one is more performant (if any)?
By the way, I'm using Material UI version 5, which claims to have better performance overall with emotion instead of JSS
makeStyles is a function from Material-UI that allows us to create CSS classes and rules using JavaScript objects. The makeStyles function returns a React hook that we can use in a functional component to access the styles and classes. Then, we can apply these styles to any element in our component.
To use the sx prop, add the custom /** @jsxImportSource theme-ui */ pragma comment to the top of your module or configure automatic JSX runtime in your transpiler. The sx prop lets you add any valid CSS to an element, while using values from your theme to keep styles consistent.
The biggest advantage of Emotion is its easily handled object styles for writing CSS. Take, for example, the case of styled-components, wherein the developer must create unique names for different components, all while avoiding identical naming styles.
JSS is slightly faster than Emotion for static styles (i.e. styles that aren't dynamic based on props). JSS is much slower than Emotion for dynamic styles -- Emotion has similar performance for both static and dynamic styles.
You can find information about the performance difference for static styles between JSS and Emotion in the following issues:
JSS was about 10% faster than Emotion for static styles. For dynamic styles, JSS was 6 times slower than Emotion in one test the Material-UI team performed, and this is why JSS was eliminated from the list of possible styling engines for v5.
The documentation at https://next.material-ui.com/system/basics/#the-sx-prop contains the following performance information:
Benchmark case | Code snippet | Time normalized |
---|---|---|
a. Render 1,000 primitives | <div className="…"> |
100ms |
b. Render 1,000 components | <Div> |
120ms |
c. Render 1,000 styled components | <StyledDiv> |
160ms |
d. Render 1,000 Box | <Box sx={…}> |
370ms |
I would expect the performance of using Emotion directly (using either the styled approach or the css prop) to be similar to Benchmark case c. I would expect makeStyles
for static styles to be slightly faster than that (in the 140ms to 150ms range), but not by much. You can see that the sx
prop is notably slower, but keep in mind that the extra 200ms of overhead is for 1,000 elements so the additional overhead is still only one-fifth of a millisecond per component rendered. The amount of overhead added by the sx
prop is dependent on how many CSS properties you pass to it. For a small number (< 5) of properties, the difference between styled
and sx
is not as significant as shown in the table above.
I don't recall seeing any claims by Material-UI that v5 is faster than v4 overall. v5 does add many new features that would have been hideously slow (due to leveraging dynamic styles) if implemented using JSS, so they were able to add those features while keeping the styling performance comparable to v4.
The biggest downside of using makeStyles
with Material-UI v5 is that you would then be causing your users to download both JSS and Emotion as part of your bundle. If you have an existing application built with v4 that already uses makeStyles
a lot (that you are now moving to v5), one migration option is tss-react which retains a similar syntax to makeStyles
, but is backed by Emotion instead of JSS and has similar performance to the styled
API. There is now a codemod for migrating JSS styles to tss-react
.
I had the same problem, but then I decided to rebuild the makeStyles overall based on @emotion/css
:
https://dev.to/atonchev/material-ui-5-the-easiest-way-to-migrate-from-makestyles-to-emotion-1i9l
Basically you will need to make one custom hook useClasses
, which will rework your theme => ({...
function or styles object into classes, that are used exact the same way like with makeStyles.
There is also IMO a huge benefit of using this approach compared to the way how it is proposed in the mui codemod:
https://github.com/mui-org/material-ui/blob/v5.0.0-beta.2/packages/material-ui-codemod/README.md#jss-to-styled
Because the emotion/css will cache same styles as one className, and you basically reuse classes, for example:
const styles1 ={
someClass1: { color: 'black' }
}
const styles2 ={
someClass2: { color: 'black' }
}
both styles1.someClass1
and styles2.someClass2
will have the same class name in production, e.g. css-1qs4g5r
. I tryed it already. But in the mui proposed codemode-way you will have unique class names, which are not really reusable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With