Codesandbox example of my issue
I’m using CSS Grid to lay out my application. The application is made up of three primary parts: Header, Menu, and Content. This is the basic structure:
<div className="application">
<div className="header">
header
</div>
<div className="menu">menu</div>
<div className="content">
content
</div>
</div>
By default the Menu is hidden with this line:
grid-template-columns: min-content 0 1fr;
When the menu is opened this is instead applied:
grid-template-columns: min-content min-content 1fr;
When clicking the Header I want to animate the menu open and resize the Content region accordingly, animating both its position and width. I’m currently doing this using framer-motion’s Layout animations.
After adding that in, this is what my markup looks like:
<motion.div className={`application${isMenuOpen ? " menuIsOpen" : ""}`}>
<motion.div
className="header"
onTap={() => setIsMenuOpen(!isMenuOpen)}
>
header
</motion.div>
<motion.div className="menu">menu</motion.div>
<motion.div
layout="position"
className="content"
>
content
</motion.div>
</motion.div>
Note: I use layout="position"
instead of just layout
to avoid the scaleX
that is applied by framer-motion when animating.
The Problem
When clicking the Header the Content region instantly shrinks to its final “menu open” width and reveals the application background until its x
is animated fully. Conversely, clicking it again makes it extend beyond the application wrapper to its “menu closed” width. If I change layout="position"
to layout
it gets me closer but of course animates the scaleX
and distorts the contents. Not good.
How do I animate the width of Content without distorting its contents?