Toniq
Toniq

Reputation: 5016

Css z-index and transform weird flash

Click on the image in snippet (expand full page) to run transform and look more closely at bottom right corner when animated card goes behind, you will see it overlaps slightly when it shouldn't. I happens when I apply z-index on each box div in CSS. If I remove z-index, there is no flash, but I need z-indexes on my box divs. Otherwise I cant have stack behave in such when I shuffle them (unless I change DOM order which I don't want). I have tried with some backface-visibility in CSS but with no luck. How could I get rid of such flash?

$('body').on('click', function() {

  var box = $('#a2')

  box.one("transitionend", function() {

    box.css("zIndex", -1).one("transitionend", function() {

    }).removeClass('t').addClass('t2')

  }).addClass('t')


})
.box {
  position: absolute;
  width: 250px;
  padding: 10px;
  background: #fff;
  box-shadow: 1px 1px 5px #484848;
  left: 0;
  top: 0;
  height: 370px;
  box-sizing: content-box;
  transition-duration: 0.5s;
  transition-timing-function: ease;
  backface-visibility: hidden;
}

.box img {
  display: block;
  position: relative;
  backface-visibility: hidden;
  user-select: none;
}

#a1 {
  z-index: 0;
  transform: rotate(-4.5884deg);
}

#a2 {
  z-index: 1;
  transform: rotate(7deg);
}

.t {
  transform: translateX(370px) rotate(23deg) !important;
}

.t2 {
  transform: translateX(0) rotate(-7deg) !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="box" id="a1">
  <img src="http://interactivepixel.net/tst/01.jpg" alt="" />
</div>

<div class="box" id="a2">
  <img src="http://interactivepixel.net/tst/02.jpg" alt="" />
</div>

Happens in all browsers from what I can see.

Upvotes: 3

Views: 990

Answers (4)

kukkuz
kukkuz

Reputation: 42370

The fix is actually simple - just add transition-property: transform because that is what you want to transform (transition-property: all is the default and z-index is also transitioned).

See demo below:

$('body').on('click', function() {
  var box = $('#a2')
  box.one("transitionend", function() {
    box.css("zIndex", -1).removeClass('t').addClass('t2')
  }).addClass('t')
});
.box {
  position: absolute;
  width: 250px;
  padding: 10px;
  background: #fff;
  box-shadow: 1px 1px 5px #484848;
  left: 0;
  top: 0;
  height: 370px;
  box-sizing: content-box;
  transition-duration: 0.5s;
  transition-timing-function: ease;
  backface-visibility: hidden;
  transition-property: transform; /* added */
}

.box img {
  display: block;
  position: relative;
  backface-visibility: hidden;
  user-select: none;
}

#a1 {
  z-index: 0;
  transform: rotate(-4.5884deg);
}

#a2 {
  z-index: 1;
  transform: rotate(7deg);
}

.t {
  transform: translateX(370px) rotate(23deg) !important;
}

.t2 {
  transform: translateX(0) rotate(-7deg) !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="box" id="a1">
  <img src="http://interactivepixel.net/tst/01.jpg" alt="" />
</div>

<div class="box" id="a2">
  <img src="http://interactivepixel.net/tst/02.jpg" alt="" />
</div>


Why the flicker?

Note that z-index is an integer and it doesn't make much sense to transition it - the animation type is integer according to MDN:

When animated, values of the data type are interpolated using discrete, whole steps. The calculation is done as if they were real, floating-point numbers; the discrete value is obtained using the floor function. The speed of the interpolation is determined by the timing function associated with the animation.

See a sample of how you can animate z-index:

div {
  position: absolute;
  border: 1px solid;
}

.container div {
  width: 100px;
  height: 100px;
}

.container .box {
  background-color: cadetblue;
  z-index: 1;
  animation: stack 5s infinite linear;
}

.box + div {
  top: 10px;
  left: 10px;
  z-index: 1;
  background-color: lightblue;
}

.box + div + div {
  top: 20px;
  left: 20px;
  z-index: 2;
  background-color: aliceblue;
}

@keyframes stack {
  50% {
    z-index: 3;
  }
}
<div class="container">
  <div class="box"></div>
  <div></div>
  <div></div>
</div>

This is why you have the flicker in your animation.

Upvotes: 3

reflexgravity
reflexgravity

Reputation: 970

I tried increasing the z-index of the succeeding image and it works.

$('body').on('click', function() {

  var box = $('#a2')
  var i=0;
  box.one("transitionend", function() {
    // increase the z-index
    $("#a1").css("zIndex", 99);
  
    box.css("zIndex", -1).one("transitionend", function() {

    }).removeClass('t').addClass('t2')

  }).addClass('t')


})
.box {
  position: absolute;
  width: 250px;
  padding: 10px;
  background: #fff;
  box-shadow: 1px 1px 5px #484848;
  left: 0;
  top: 0;
  height: 370px;
  box-sizing: content-box;
  transition-duration: 0.5s;
  transition-timing-function: ease;
  backface-visibility: hidden;
}

.box img {
  display: block;
  position: relative;
  backface-visibility: hidden;
  user-select: none;
}

#a1 {
  z-index: 0;
  transform: rotate(-4.5884deg);
}

#a2 {
  z-index: 1;
  transform: rotate(7deg);
}

.t {
  transform: translateX(370px) rotate(23deg) !important;
}

.t2 {
  transform: translateX(0) rotate(-7deg) !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="box" id="a1">
  <img src="http://interactivepixel.net/tst/01.jpg" alt="" />
</div>

<div class="box" id="a2">
  <img src="http://interactivepixel.net/tst/02.jpg" alt="" />
</div>

Upvotes: 0

Hassan Siddiqui
Hassan Siddiqui

Reputation: 2845

I just update your code with jQuery update. Actually i just move your box.css("zIndex", -1).addClass('t'); script in setTimeout method. Try this I hove it'll resolve your issue. Thanks

$('body').on('click', function() {

  var box = $('#a2')
  box.one("transitionend", function() {
    box.one("transitionend").addClass('t2');
  })
  setTimeout(function(){
    box.css("zIndex", -1).addClass('t');
  })

})
.box {
  position: absolute;
  width: 250px;
  padding: 10px;
  background: #fff;
  box-shadow: 1px 1px 5px #484848;
  left: 0;
  top: 0;
  height: 370px;
  box-sizing: content-box;
  transition-duration: 0.5s;
  transition-timing-function: ease;
  backface-visibility: hidden;
}

.box img {
  display: block;
  position: relative;
  backface-visibility: hidden;
  user-select: none;
}

#a1 {
  z-index: 0;
  transform: rotate(-4.5884deg);
}

#a2 {
  z-index: 1;
  transform: rotate(7deg);
}

.t {
  transform: translateX(370px) rotate(23deg) !important;  
}

.t2 {
  transform: translateX(0) rotate(-7deg) !important;  
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="box" id="a1">
  <img src="http://interactivepixel.net/tst/01.jpg" alt="" />
</div>

<div class="box" id="a2">
  <img src="http://interactivepixel.net/tst/02.jpg" alt="" />
</div>

Upvotes: 0

thetont
thetont

Reputation: 810

I think it is merely an order problem. Just place the .css (" zIndex ", -1) next to the .addClass ('t'): this way flash doesn't happen since z-index is applyed before the backward translation

$('body').on('click', function() {
  var box = $('#a2')
  box.one("transitionend", function() {
    box.removeClass('t').addClass('t2')
  }).css("zIndex", -1).addClass('t')
})

Upvotes: 0

Related Questions