css breaks in production of Gatsby, MaterialUI

Viewed 1557

I have a gatsby website that uses MaterialUI Components.

Somehow the css styles get applied to the wrong components of my website. I got the following code that is related to the problem.

Layout.js

    <ThemeProvider theme={theme}>
      <CssBaseline/>
      <Header onMenu={() => setMenuOpen(true)}/>
      {children}
    </ThemeProvider

Header.js

const NavigationBar = ({onMenu}) => {
  const trigger = useScrollTrigger({target: (typeof window !== `undefined` ? window : undefined)})
  const data = useStaticQuery(query)
  return (
    <React.Fragment>
      <Slide appear={false} direction="down" in={!trigger}>
        <AppBar color={"primary"}>
          <Toolbar disableGutters={true}>
           ...
            <LaptopAndWider>
              {data.dataJson.navigationPrimary.map(x =>
                <Button key={x.title} component={Link} to={x.path} color="inherit" underline={"none"}>
                  <Box height="70" alignItems="center" justifyContent="center" display="flex"> // This styles (height, flexBox) gets applied to the wrong item
                    <Typography variant={"h6"}>
                      {x.title}
                    </Typography>
                  </Box>
                </Button>
              )}
              {data.dataJson.navigationSecondary.map(x =>
                <Button key={x.title} component={Link} to={x.path} color="inherit" underline={"none"}>
                  <Box height="70px" alignItems="center" justifyContent="center" display="flex">
                    <Typography variant={"body1"}>
                      {x.title}
                    </Typography>
                  </Box>
                </Button>
              )}
            </LaptopAndWider>
           ...
          </Toolbar>
        </AppBar>
      </Slide>
      <Box height={82}/>
    </React.Fragment>
  );
}

And the following index.js

const IndexPage = ({data}) => (
  <React.Fragment>
    <Box> // Gets applied to this Box
      <GatsbyImage fluid={data.file.childImageSharp.fluid}
                   />
    </Box>
    ...
  </React.Fragment>
)

I use the following plugins in gatsby which could be related:

  plugins: [
    ...
    `gatsby-theme-material-ui`,
    `gatsby-plugin-emotion`,
    {
      resolve: `gatsby-plugin-layout`,
      options: {
        component: require.resolve(`./src/components/Layout`),
      },
    }
  ],

When I use gatsby develop, the jss/css is working as expected. But in Production (gatsby build && gatsby serve) the css which is applied to the navigation bar items (<Box height="70" alignItems="center" justifyContent="ce....) is applied to the Box which surrounds my Image. This is just one of the Problems that happen in production, just to show the Problem. All styles are odd and broken in prod.

CSS on the NavigationBar Item enter image description here

CSS on the Div around the gatsby-image (which should have no styles) enter image description here

What I have tried:

  • Removed gatsby-plugin-offline (That seems to cause Problems, dont need it atm anyway)
  • Reordered components on all kinds of pages
  • Removed gatsby-plugin-emotion (no changes)
  • Removed .cache node_modules and package-lock.json and reinstalled packages
  • Updated all packages
  • Replace the rehydrate function with render (which did break even more things)
  • Read to a bunch of related gitlab issues, which mostly suggest removing the gatsby-offline-plugin, clearing caches and updating packages.

A sample that shows the problem is available here: https://github.com/Console32/BrokenCss

2 Answers

The problem originates from the LaptopAndWider component. This component uses MediaQuery from react-responsive to implement hiding things on different screen sizes. The SSR did therefore never render the Material UI Components below LaptopAndWider, which resulted in missing styles. CSR did work, which is why after navigating back and forth the correct styles where applied.

Replacing MediaQuery from react-responsive with Hidden from @material-ui/core solves the problem.

            <Hidden mdDown>
              {data.dataJson.navigationPrimary.map(x =>
                <Button key={x.title} component={Link} to={x.path} color="inherit" underline={"none"}>
                  <Box height="70" alignItems="center" justifyContent="center" display="flex"> // This styles (height, flexBox) gets applied to the wrong item
                    <Typography variant={"h6"}>
                      {x.title}
                    </Typography>
                  </Box>
                </Button>
              )}
              {data.dataJson.navigationSecondary.map(x =>
                <Button key={x.title} component={Link} to={x.path} color="inherit" underline={"none"}>
                  <Box height="70px" alignItems="center" justifyContent="center" display="flex">
                    <Typography variant={"body1"}>
                      {x.title}
                    </Typography>
                  </Box>
                </Button>
              )}
            </Hidden>

This conflict with the CSS classnames results from having a multitree setup in your application.

You can resolve this conflict by providing a classname generator for generating the classes. This way Gatsby and MDX will use the same classname generator to generate classnames.

Install react-jss

yarn add react-jss

In src/components/Layout.js, provide the same classname generator,

import React from 'react';
//...
import {createGenerateId, JssProvider} from 'react-jss';

const generateId = createGenerateId();

const Layout = ({children}) => {  
  //...
  return ( 
    <JssProvider generateId={generateId}>
      <ThemeProvider theme={theme}>
      {/* ... */}
      </ThemeProvider>
    </JssProvider>
  );
}
Related