Search code examples
csscss-transitionscss-transforms

Why does transition-delay not work on a child element when parent is shown?


This is probably best illustrated with an example. I have a parent and a child. The parent is hidden by default unless it has an in class. Its child should transition its background-color from green to white, after a 3s delay, only once the parent receives the in class.

So when the parent is shown, the child's background color is already white. There's no 3 second period of orange, with a transition to white. Can someone explain what's happening here?

$('button.show').on('click', () => {
  $('.parent').addClass('in');
});

$('button.hide').on('click', () => {
  $('.parent').removeClass('in');
});
.parent, .child {
  display: flex;
  align-items: center;
  justify-content: center;
}

.parent {
  background-color: orange;
  width: 300px;
  height: 300px;
}

.child {
  background-color: green;
  padding: 20px;
  width: 150px;
  height: 150px;
  transition: background-color 1s linear;
}

.parent:not(.in) {
  display: none;
}

.parent.in .child {
  background-color: white;
  transition-delay: 3s;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="parent">
  <div class="child">
    <span>Background should start green, then turn white, but transition isn't happening.</span>
  </div>
</div>

<br>
<button type="button" class="show">Show parent</button>
<button type="button" class="hide">Hide parent</button>


Solution

  • I got a bit confused with exactly when the settings would occur given the display:none starting condition on the parent.

    This snippet takes a slightly different path - using a CSS animation which I found easier to control. The animation is not set up until the parent is displayed so there is no room for confusion on timing.

    $('button.show').on('click', () => {
      $('.parent').addClass('in');
    });
    
    $('button.hide').on('click', () => {
      $('.parent').removeClass('in');
    });
    .parent,
    .child {
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    .parent {
      background-color: orange;
      width: 300px;
      height: 300px;
    }
    
    .child {
      background-color: green;
      padding: 20px;
      width: 150px;
      height: 150px;
      animation-name: none;
    }
    
    .parent:not(.in) {
      display: none;
    }
    
    .parent.in .child {
      animation-name: change;
      animation-duration: 1s;
      animation-iteration-count: 1;
      animation-delay: 3s;
      animation-fill-mode: forwards;
    }
    
    @keyframes change {
      0% {
        background-color: green;
      }
      100% {
        background-color: white;
      }
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <div class="parent">
      <div class="child">
        <span>Background should start green, then turn white, but transition isn't happening.</span>
      </div>
    </div>
    
    <br>
    <button type="button" class="show">Show parent</button>
    <button type="button" class="hide">Hide parent</button>