Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] AnimatePresence height animation with padding doesn't work #368

Closed
snowl opened this issue Oct 18, 2019 · 22 comments 路 Fixed by #1321
Closed

[BUG] AnimatePresence height animation with padding doesn't work #368

snowl opened this issue Oct 18, 2019 · 22 comments 路 Fixed by #1321
Labels
bug Something isn't working wontfix This will not be worked on

Comments

@snowl
Copy link

snowl commented Oct 18, 2019

1. Read the FAQs 馃憞

2. Describe the bug

When using AnimatePresence with some padding in the div that you are animating w/ height animation, the height calculation breaks and only animates the height to the (internal height - padding), both in and out.

3. IMPORTANT: Provide a CodeSandbox reproduction of the bug

https://codesandbox.io/s/framer-motion-animatepresence-padding-issue-zqxrk?fontsize=14

If you remove the padding: within the div css, you can see how much more smooth the animation is.

4. Steps to reproduce

Animate height on a div that has padding.

5. Expected behavior

Height should go from 0 to the height calculated by the browser for "auto".

6. Video or screenshots

Here's a gif of how it looks in my application: https://gfycat.com/weirdachingdogwoodclubgall

You can see the div underneath "snaps" because of all the height that still exists due to the padding.

7. Environment details

Tested in chrome

@snowl snowl added the bug Something isn't working label Oct 18, 2019
@thebuilder
Copy link
Contributor

I don't think this a framer motion bug. You'd see this regardless of how you are animating height.
It's how the browsers deal with padding when height is 0.

@snowl
Copy link
Author

snowl commented Oct 20, 2019

I don't think so - if you slow down the transitions down so you can observe the values they end up animating from "auto" to the total padding height instead of animating from "auto" to 0. Also - even if you try and set the animation to:

<motion.div
                key={item}
                animate={{ height: "auto", opacity: 1, paddingTop: 30, paddingBottom: 30 }}
                exit={{ height: 0, opacity: 0, paddingTop: 0, paddingBottom: 0 }}
                initial={{ height: 0, opacity: 0, paddingTop: 0, paddingBottom: 0 }}
              >

Not only does it exhibit the same behavior, but it also now "snaps" in when animating in as well. I'm fairly sure that this should be animating smoothly here.

@rijk
Copy link

rijk commented Oct 22, 2019

I have noticed this behaviour as well when testing with height: 'auto'. I also think it鈥檚 a Framer Motion measuring bug.

@vavra7
Copy link

vavra7 commented Jun 28, 2020

Any updates on this? The problem is still present.

@cjoecker
Copy link

I used until this is fixed a work around with Material-UI transitions:

import { Collapse } from '@material-ui/core';
import { motion, useIsPresent } from 'framer-motion';
import React, { memo, useEffect, useState } from 'react';

interface CollapseAnimationProps {
  id: number;
  children: React.ReactNode;
}

function _CollapseAnimation({ id, children }: CollapseAnimationProps) {
  const isPresent = useIsPresent();
  const [isVisible, setIsVisible] = useState(false);

  const ANIMATION_TIME = 500;

  useEffect(() => {
    const timeout = setTimeout(() => setIsVisible(true), 0);
    return () => clearTimeout(timeout);
  }, []);

  useEffect(() => {
    if (isVisible && !isPresent) {
      setIsVisible(false);
    }
  }, [isPresent, isVisible]);

  return (
    <motion.div
      key={id}
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
      transition={{ duration: ANIMATION_TIME / 1000 }}
    >
      <Collapse in={isVisible} timeout={ANIMATION_TIME}>
        {children}
      </Collapse>
    </motion.div>
  );
}
//Don't use framer motion height animation until this bug is solved:
//https://github.com/framer/motion/issues/368

export const CollapseAnimation = memo(_CollapseAnimation);

@andria-dev
Copy link

andria-dev commented Dec 30, 2020

Can confirm this is not the browser's fault. I slowed down the animation and it looks like Framer Motion is stopping the animation for the height at an early number. Even if you animate the padding to 0 it stops early. For me it's stopping at like 20px for no reason. If I take away all padding animations, it works fine.

@mattgperry
Copy link
Collaborator

Yeah it's definitely a mis-measurement because of the padding. I'll have to look into it.

@ardiewen
Copy link

For now, this can be solved with height: auto animating on an outside container without padding, and set padding on an inner container.

@MikeWillis
Copy link

For me @ardiewen's solution worked when collapsing a div, but unfortunately not when opening it. Still better though

@oORiggsOo
Copy link

oORiggsOo commented Aug 13, 2021

<motion.div
                key={item}
                animate={{ height: "100px", opacity: 1, paddingTop: "30px", paddingBottom:  "30px"}}
                exit={{ height: "0px" opacity: 0, paddingTop: "0px", paddingBottom: "0px" }}
                initial={{ height: "0px", opacity: 0, paddingTop: "0px", paddingBottom: "0px" }}

This worked for me
.. make sure you close ya values with double quotes, and add the px value on items that would justify marked with px

@kylemh
Copy link

kylemh commented Sep 20, 2021

This bug extends to border as well.

@mattgperry
Copy link
Collaborator

I'm just looking into this now. The behaviour in the original post isn't a bug. When height is animated to 0, height is animated to 0. But of course with CSS that doesn't mean the actual height is going to be 0 because padding still exists.

The snapping in this example: #368 (comment) is a bug and maybe something we can do something about

@mattgperry
Copy link
Collaborator

#1321 (comment)

@mattgperry mattgperry reopened this Nov 9, 2021
@present-g
Copy link

Hi! When can we expect a fix?

@amogadasi
Copy link

amogadasi commented Feb 20, 2022

moving the padding to an inner div solved it for me:

https://codesandbox.io/s/framer-motion-animatepresence-padding-issue-forked-317ykj

@marcospassos
Copy link

This bug makes the DX really bad. Using borders, margins, and padding is almost unavoidable for use cases like lists. Currently require a lot of boilerplate code to make it work smoothly.

@mattgperry mattgperry added the wontfix This will not be worked on label Jun 1, 2022
@mattgperry
Copy link
Collaborator

mattgperry commented Jun 1, 2022

Closing this out with a wontfix. The official workaround is to apply padding to an inner div.

If you visit the sandbox I reopened this ticket with: https://codesandbox.io/s/framer-motion-animatepresence-padding-issue-8wi8n?file=/src/index.js

  1. Inspect one of the items.
  2. Go to the console, run $0.getBoundingClientRect()
  3. See that height is 79px
  4. Padding is currently 30 on both sides. 79 - 30 - 30 = 19
  5. Set height from auto to 19px
  6. See height change in the same manner as the jump. This is where I nope out 馃槄

I suspect in this specific example something is going on with line-height and the auto calculation. Either way this is firmly in "juice ain't worth the squeeze" territory.

@mattgperry
Copy link
Collaborator

Added to the bug template FAQs https://github.com/framer/motion/blob/main/.github/ISSUE_TEMPLATE/bug_report.md

@soufDev
Copy link

soufDev commented Aug 9, 2022

hello 馃憢 @mattgperry

I tried your workaround, unfortunately the animation is not really working if we add padding to the inner div 馃槩

I have to delete it to have the smooth animation

You can have a look at the video just bellow

Please I would really need help on this one 馃檹

Kapture.2022-08-09.at.23.24.06.mp4

@minlare
Copy link

minlare commented Oct 27, 2022

I had this issue when using display: grid and row-gap. Tweaking the html to add a wrapping element to each list item with padding instead of row-gap works perfectly!

@adomaitisc
Copy link

I was having the same issue of jumping animation with padding.
Then, I decided to not use padding at all.

I am using empty p tags with the height of the padding I need.

image

I can say that it works.

Not a huge workaround but not pretty as well. And it is only a 'hack' until something official comes in.

Thanks!

@merlindru
Copy link

If it still doesn't work, one way to solve this is to use something like @react-hook/size, to measure the size of your inner div and then pass that to framer-motion explicitly:

const ref = useRef<HTMLDivElement | null>(null);
const [width, height] = useSize(ref);

<motion.section
    animate={active ? "active" : "idle"}
    variants={{
        idle: { height: 50 },
        active: { height: height },
    }}
>
    <motion.div ref={ref}> ... </motion.div>
</motion.section>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working wontfix This will not be worked on
Projects
None yet
Development

Successfully merging a pull request may close this issue.