Search code examples
javascriptcssanimationtransition

Why is my container transition not smooth when grids get appended?


I'm at a bit of a loss on my transition animation, I've replicated the problem in a codepen to share.

When I click the button, it creates two grids. Then applies a class to the bottom container to shift its Y position down the page. A setTimeout waits for this transition to end and then it appends these two grids to the main container.

But as you'll notice, after the animation has occurred it pushes the bottom container further down the page and i can't figure out why. I asked chatGPT but it wasn't able to come up with any potential solutions.

As I said, I've tried various ways to wait for the transitionend of the container, but it always seems to jump down, and i can't seem to get a seamless transition from its starting position to below the grids.

The related animation is happening on the transition-container style here:

.grid.left,
.grid.right {
    display: flex;
    transform: scale(0);
    background: var(--main-background-clr);
    border-radius: 5px;
    flex-shrink: 0;
    width: 50%;
    height: 100%;
    aspect-ratio: 1/1;
    transition: 700ms ease;

}

.grid.left.visible,
.grid.right.visible {
    transform: scale(1);
}

.transition-container {
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    gap: 20px;
    width: 100%;
    transition: all 0.5s ease;
}

.transition-container.shift-down {
    transform: translateY(100%);
}
.ship-main-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding-top: 10px;
    gap: 20px;
    width: 100%;
    height: 200px;
    background: var(--grid-border-clr);
}

This is the JavaScript code which generates the grid and adds the shifted class to the container, then waits 500ms before appending the grids to the top container :

    const generateGrids = () => {
        const mainBoardsContainer = document.querySelector('.gameboards');

        const shipMainContainer = document.querySelector('.ship-main-container');
        const transitionContainer = document.querySelector('.transition-container');

        
        const playerBoard = document.createElement('div');
        const computerBoard = document.createElement('div');
        
        playerBoard.className = 'grid left';
        
        computerBoard.className = 'grid right';
        
        playerBoard.dataset.grid = false;

        makeGridSquares(playerBoard, false);
        makeGridSquares(computerBoard, true);

 

        transitionContainer.classList.add('shift-down');

        setTimeout(() => {
            mainBoardsContainer.append(playerBoard, computerBoard);
            playerBoard.classList.add('visible');
            computerBoard.classList.add('visible');
        }, 500);

        
    }

Here is my codepen if you'd like to see the full code: https://codepen.io/itswakana/pen/poObOYQ


Solution

  • I would go about this one of two ways. Rather than using the translateY property on the transition-container class, I would set the position to absolute and use the top property to handle the transition...also give it a height.

        .transition-container {
          ...your other css properties;
          height: min-content;
          position: absolute;
          top: 0vh;
        }
    
        .transition-container.shift-down {
          top: 100vh;
         }
    

    This will give you that smooth transition. That's the quick fix. A more detailed approach would be to wrap everything in a main-container div.

           <div class="main-container">
             <div class="gameboards">
             </div>
             <div class="transition-container">
               <div class="ship-main-container"></div>
               <button class="start-game">Start Game</button>
             </div>
           </div>
    

    Give that sucker some styles:

         .main-container {
           display: flex;
           flex-direction: column;
           height: -webkit-fill-available; (or 100%)
           justify-content: flex-start;
           width: 100%;
         }
    

    Now, if you know the split in height between gameboards and transition-container, you can set the transition-container to the desired height (not really necessary but I think its nice to have a height for both) and give the gameboards a height: 0% that you will then add a class to it that will transform the height to whatever the desired split is. You would just have to make sure you handle the timing correctly so that your rows are inserted after the height is set on gameboards.

    Do note you could probably just put the main-container styles on the body element but I prefer using divs when creating my layout vs styling my body element. I hope this helps.