Search code examples
cssoverflowcss-animationsz-index

Adding an `animation` declaration messes up the z-indexes, kind of


Using Bootstrap's native classes, I have a list of .list-group-item elements, in which there are some clickable options, shown as dropdowns in the .dropdown-menu. By default this works fine, even when the dropdown of one .list-group-item element goes over the one below it.

What I've added then, is an animation declaration that fades in the .list-group-items by using @keyframes animation going from opacity:0 to opacity:1. And as a side-effect of that, every .list-group-item element goes visually over the dropdown menu from the previous one.

(there aren't actually any z-index declarations involved, I've only used that term in the title to illustrate the manifestation of the issue)

I am wondering if there is some kind of workaround for this overflowing issue that would allow me to keep the fade-in animation for the elements?

An example can be seen on the following fiddle (there is no javascript involved or included there as it is not necesarry, so both of the dropdowns are just declared as open in the HTML code to illustrate the situation):

https://jsfiddle.net/o8ysz4qp/2/

HTML:

<div class="list-group-item fade-in">
  <div class="pull-right dropdown open">
    <button class="btn btn-primary">
      &darr;
    </button>
    <ul class="dropdown-menu">
      <li><a href="#">One</a></li>
      <li><a href="#">Two</a></li>
      <li><a href="#">Three</a></li>
    </ul>
  </div>
  <p>Lorem ipsum dolor sit amet</p>
</div>

<div class="list-group-item fade-in">
  <div class="pull-right dropdown open">
    <button class="btn btn-primary">
      &darr;
    </button>
    <ul class="dropdown-menu">
      <li><a href="#">One</a></li>
      <li><a href="#">Two</a></li>
      <li><a href="#">Three</a></li>
    </ul>
  </div>
  <p>Lorem ipsum dolor sit amet</p>
</div>

CSS:

.fade-in {
  opacity: 0; 
  animation:fade-in .5s ease; 
  animation-fill-mode: forwards;
  animation-delay:1s;
}
@keyframes fade-in {
  from { opacity:0; }
  to { opacity:1; }
}

Solution

  • The problems is that when the opacity is not 1 it creates a new stacking context (See The stacking context - CSS | MDN)

    A solution is to add a z-index (since it becomes usable after the opacity change) and reverse their value (the last one has the lowest z-index etc)

    Something like (assuming they are siblings)

    @import url('https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css');
    
    .list-group-item:nth-last-child(1){z-index:1}
    .list-group-item:nth-last-child(2){z-index:2}
    .list-group-item:nth-last-child(3){z-index:3}
    .list-group-item:nth-last-child(4){z-index:4}
    .list-group-item:nth-last-child(5){z-index:5}
    .list-group-item:nth-last-child(6){z-index:6}
    .list-group-item:nth-last-child(7){z-index:7}
    
    .fade-in {
      opacity: 0; 
      animation:fade-in .5s ease; 
      animation-fill-mode: forwards;
      animation-delay:1s;
    }
    @keyframes fade-in {
      from { opacity:0; }
      to { opacity:1; }
    }
    <div class="list-group-item fade-in">
      <div class="pull-right dropdown open">
        <button class="btn btn-primary">
          &darr;
        </button>
        <ul class="dropdown-menu">
          <li><a href="#">One</a></li>
          <li><a href="#">Two</a></li>
          <li><a href="#">Three</a></li>
          <li><a href="#">Four</a></li>
        </ul>
      </div>
      <p>Lorem ipsum dolor sit amet</p>
      <p>Lorem ipsum dolor sit amet</p>
      <p>Lorem ipsum dolor sit amet</p>
    </div>
    <div class="list-group-item fade-in">
      <div class="pull-right dropdown open">
        <button class="btn btn-primary">
          &darr;
        </button>
        <ul class="dropdown-menu">
          <li><a href="#">One</a></li>
          <li><a href="#">Two</a></li>
          <li><a href="#">Three</a></li>
          <li><a href="#">Four</a></li>
        </ul>
      </div>
      <p>Lorem ipsum dolor sit amet</p>
      <p>Lorem ipsum dolor sit amet</p>
      <p>Lorem ipsum dolor sit amet</p>
    </div>