Search code examples
javascripthtmlcssreact-transition-group

Trouble with CSS transition, absolute positioning, and React Transition Group


I'm working on some basic FreeCodeCamp challenges, and I'm trying to use React Transition Group to achieve some pretty simple animations. Here's the CodePen.

What I've run in to is that I can't find out how to have the "quote card" horizontally and vertically centered, and also have my animations (that I'm using React Transition Group to trigger) perform a translation on it. I have the element that I'm trying to move (#quote-box) centered with the following css:

position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);

Here're the "move" CSS classes that I'm using with the Transition Group:

.move-enter {
  opacity: 0.01;
  transform: translate(-200px, 0);
}

.move-enter-active {
  opacity: 1;
  transform: translate(0, 0);
  transition: all 500ms ease-in 200ms;
}

.move-exit {
  opacity: 1;
  transform: translate(0, 0);
}

.move-exit-active {
  opacity: 0.01;
  transform: translate(200px, 0);
  transition: all 500ms ease-in 200ms;
}

I assume that I should be setting the transition properties to be left instead of all, but I'm a little lost in what is preventing the movement from happening. Should I also have a move-exited and move-entered class with the appropriate positioning? Thanks in advance!


Solution

  • There is a pretty major hint as to what might be going wrong here, and that is the fact that in your CodePen, the cards successfully animate their opacity but not their transform. That tells you that something is working as expected, just not all of the transition.

    So, our first step would be to investigate the transition as it happens. Indeed, if we slow down the CSS transition duration to 20 seconds and set the <ReactTransitionGroup.CSSTransition> timeout also to 20 seconds, and inspect the element div#quote-box with devtools as the transition is happening, we see something fishy:

    enter image description here

    Your CSS transform property for #quote-box is overriding the transition group transform property for .move-enter-active (as expected - see CSS selector specificity) (you can tell because the transform property in .move-enter-active is crossed out). In other words, your CSS transition group transform is never applied, but the opacity transition is unaffected because #quote-box does not set that property.

    There are a few potential solutions here. One of the most simple involves two steps:

    1. Change #quote-box from an ID to a class (.quote-box) - (you should absolutely do this anyway, and also for any IDs on the page, because you should only ever have a single instance of the same named ID on the page, and with CSS transition group you will have at least two at some points.) This will also ensure that your CSS transition group .move-* selectors will have the proper priority.
    // CSS
    .quote-box {
      // etc
    }
    
    // JSX
    <div className="quote-box" >
      {/* etc */}
    </div>
    
    1. Adjust your CSS to use the calc() function to calculate the position of the quote box. This is because normally you would not be able to center the quote box with transform(-50%, -50%) and offset its position for the transition with transform(-200px, 0) at the same time. To do so, we must use calc() to combine both the centering transform and the transition offset at the same time, i.e. transform: translate(calc(-50% - 200px), -50%);:
    .move-enter {
      opacity: 0.01;
      transform: translate(calc(-50% - 200px), -50%);
    }
    
    .move-enter-active {
      opacity: 1;
      transform: translate(-50%, -50%);
      transition: all 500ms ease-in 200ms;
    }
    
    .move-exit {
      opacity: 1;
      transform: translate(-50%, -50%);
    }
    
    .move-exit-active {
      opacity: 0.01;
      transform: translate(calc(-50% + 200px), -50%);
      transition: all 500ms ease-in 200ms;
    }
    

    https://codepen.io/_jered/pen/KKPomVK