Search code examples
reactjsnext.jsframer-motion

Layout shift on exit animation with Framer Motion and NextJS


I have a website that I'm doing where one page flashes a Layout Shift on visiting another page. No other page does this, and I'm not sure how to figure it out. If somebody has some Framer Motion insight they'd like to share with me on how to troubleshoot this, I'd be most grateful. I've also found out that when it's in development it doesn't happen, but when I deploy to production, it does.

The page: https://krista-doubleday--preview-apq5vrih.web.app/contact

Here is the code for that page:

import { Button, Grid, Typography, useMediaQuery } from '@material-ui/core'
import Image from '../components/Image'
import styles from '../styles/Contact.module.scss'

export default function Contact(props) {
  const isMobile = useMediaQuery('(max-width: 1279px)')

  return (
    <Grid container className={ styles.bg } direction="column" justifyContent={isMobile ? 'start' : 'center'} alignItems="center" style={{minHeight: '100vh'}}>
      <Grid container direction="row" flexWrap="wrap-reverse" justifyContent="center" alignItems="center" style={{ maxWidth: '2000px' }}>
        <Grid item className={styles.contact} style={{ margin: isMobile ? '-10% 0px 0px 0px' : '0px -10% 0px 0px', padding: '2em', zIndex: 2 }}>
          <Grid item xs={12} lg={6} justifyContent="center" className={styles[`contact-card`]}>
            <Typography variant="h3" style={{marginBottom: '1rem'}}>Contact Me</Typography>
            <Typography>Krista Doubleday, M.COUN, LCPC, NCC</Typography>
            <Typography><b>Call/Text:</b> {<a href="tel:2083665616">208.366.5616</a>}</Typography>
            <Typography><b>Fax:</b> 208.362.7083</Typography>
            <Typography><b>Email:</b> {<a href="mailto:[email protected]" target="_blank">[email protected]</a>}</Typography>
            <br />
            <Typography><b>Address:</b></Typography>
            <Typography>{<a href="https://goo.gl/maps/jVcih9ihFSB2weAv7" target="_blank">3709 N Locust Grove Rd, Suite 100 <br />Meridian, ID 83646</a>}</Typography>
            <Grid item style={{ marginTop: '1rem' }}>
              <Button variant="contained" color="lavender"><a href="https://krista-doubleday.clientsecure.me/" target="_blank" style={{textDecoration: 'none'}}><Typography variant="button" style={{color: '#ffffff'}}>Client Portal</Typography></a></Button>
            </Grid>
          </Grid>
        </Grid>
        <Grid item xs={12} lg={6}>
          <Image divClasses={styles[`inner-frame`]} src="/images/contact.jpg" style={{ minHeight: '600px', maxWidth: '100%', objectFit: 'cover' }} />
        </Grid>
      </Grid>
      <Typography variant="subtitle1" style={{ marginTop: '1rem', textAlign: 'center' }}>Can you see yourself here? Call, text, or email me to set up your free 15 minute phone consultation. I look forward to hearing from you.</Typography>
    </Grid>
  )
}

Here is the CSS:

.bg {
  position: relative;
  z-index: 1;

  &::before {
    position: absolute;
    content: "";
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: url("/images/email-pattern.png");
    background-attachment: fixed;
    background-size: 600px;
    opacity: 0.65;
    z-index: -1;
  }
}

.contact {
  position: relative;
  border-right: 2rem solid #c0debb;
  background-color: #ffffff;
  white-space: nowrap;
  max-width: 100%;

  & p {
    font-size: calc(0.6vmin + 10px);
  }
}

.contact-card {
  width: 600px;
  max-width: 80vw;
}

.inner-frame {
  position: relative;

  & ::before {
    content: "";
    position: absolute;
    top: 20px;
    bottom: 20px;
    left: 20px;
    right: 20px;
    border: 2px solid #ffffff;
  }

  & img {
    display: block;
    width: 100%;
    height: auto;
  }
}

If you click on any link in the bar, you'll see the two divs lose their positioning. Any help is appreciated!


Solution

  • I managed to trace the issue to the CSS modules. Basically, when the page change happens, all of the CSS modules are destroyed, using the new page's CSS module instantly. Therefore, all of the associated styling was broken because Motion just 'saves' the component state while animating out - not the stylesheet.

    I've since just switched to JSS using makeStyles() and the problem is now gone. :)