Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

webkit translate3d issues (peek-thru)

I'm building an iOS app with PhoneGap. I'm using translate3d CSS animations to create the 'flip' effect.

This works great on simpler elements...a DIV with front/back divs and maybe an extra span or two.

But when I attempt to flip a larger element...namely the entire screen, I get redraw glitches. What happens as soon as I swap the css class to start the transition, parts of the 'bottom' div pop-through the 'top' div, then the flip happens, then they pop-out again. And it's not the entire element that shows through...it's half of the element split along the axis that I'm doing the translate 3d rotation on.

Any ideas or theories as to what might be causing this? It happens the same both on the iPad as an app and on the desktop in Safari, so appears to be a webkit issue.

Could it be some CSS issues? Or is attempting to do a full-screen translate3d rotation with complex nested elements with large background images just more than Safari can handle?

UPDATE 1:

I've made progress in narrowing down the issue.

What's happening is that the elements that are 'peeking through' when I do the translate3d flip happen to be child elements that had been previously positioned via translate3d.

My 'page' structure that I want to transition with translate3d:

<div id="frontbackwrapper">
    <div id="front">    
    </div><!--/front-->
    <div id="back">  
    </div><!--/back-->
</div><!--/frontbackwrapper-->  

This works on it's own. The front div is replaced with the back div with a card-flip effect.

The problem is that prior to doing the full page flip, I've already animated some elements within the #front div using translate3d:

<div id="frontbackwrapper">
    <div id="front">  

        <div class="modal"></div>  

    </div><!--/front-->
    <div id="back">  
    </div><!--/back-->
</div><!--/frontbackwrapper--> 

Example CSS:

.modal {
    width: 800px;
    height: 568px;
    position: absolute; 
    left: 112px;
    z-index: 100;
    -webkit-transition-duration: 1s;
    -webkit-transform: translate3d(0,-618px,0); /* set off screen by default */
 }
.modal.modalOn {
    -webkit-transform: translate3d(0,80px,0); /* slides the div into place */
 }

If--instead of using translate3d--I just reposition the div with a top style or transform the top property, I don't get the peek-through issue. Of course, that means I have to give up the slick animation or hardware acceleration, respectively.

At this point, it looks like a webkit bug. I'll keep doing some playing with it. If anyone has run into this before and found a workaround, I'm all ears!

like image 470
DA. Avatar asked Jul 03 '11 18:07

DA.


2 Answers

solution! After a night of sleep, I mulled over the culprit and what to do with it. It's not necessarily the act of animating a child element with translate3d but rather the face that the element that was translated has that CSS property at the time it's parent is being animated with translate3d.

The fix is to first animate the child element, then remove the translate style all together.

The CSS structure is now:

/* default class for the start of your element */
.modal-startposition {
  -webkit-transition-duration: 1s;
  -webkit-transform: translate3d(0,-618px,0);
  }

/* add this class via jQuery to then allow
   webkit to animate the element into position */
.modal-animateposition {
  -webkit-transform: translate3d(0,80px,0);
}

/* when animation is done, remove the above class
   and replace it with this */
.modal-endposition {
  top: 80px;
}

And some sample jQuery:

//[attach a click event to trigger and then...]
$myModal
    .addClass("modal-animateposition")
    .on('webkitTransitionEnd',function () {
         $myModal
            .removeClass('modal-startposition')
            .removeClass('modal-animateposition')
            .addClass('modal-endposition');
    });

A little tedious, but it completely fixes the screen redrawing problem.

EDIT: Corrected a typo

like image 138
DA. Avatar answered Sep 21 '22 05:09

DA.


DA, I learned something from this, thanks. Also, take note of the css attrbibutes, 'translate3d' and 'left'. Translating and positioning is a little different. Test it out, translate an element 100px in x-axis, set it's 'left' style attribute to 0px. Verify, it will be positioned at 0px on x-axis from the current translation point (starting from 100px on x-axis).

That produces mathematical errors in drag/drop and animation algorithms and easily noticed (redraw glitches, skips, position getting reset), and becomes a challenge because translate3d no longer updates the elements offsetLeft or 'left' style attribute (to prevent reflow, for optimization), so parsing the elements real left, is based on knowing if translate3d or left was being used. If you're a game developer, tracking the x,y in internal variables is the way to stay in synch with the elements position. Hope that helps out more.

like image 25
jaysmith024 Avatar answered Sep 21 '22 05:09

jaysmith024