title: CSS 3D : rotateY + translateX make elements flicker during in Firefox
body: <p>I need to implement a "room" 3d rotation on some elements; to achieve it <code>transform: translateX(-100%) rotateY(90deg)</code> and its opposite transition are used. It works fine in Chrome, but <strong>in Firefox</strong> (up to the version 34) the elements flicker during the transition. They can do so just for a moment, having gone half the way, or disappear completely.</p>
  
  <p>What I have noticed: if the <code>perspective</code> CSS value on the parent is higher than the computed width of the elements in question - the transition goes well. If the perspective is really a culprit, then I don't understand the nature of such behaviour; the specs say, an element isn't drawn if Z-axis value of <strong>all its points</strong> is lower than the perspective value. And mine should definitely be visible at least partially during the transition.</p>
  
  <p>It should be noted, that only rotateY seems buggy - not the rorateX.</p>
  
  <p>Here are the code samples. The html:</p>
  
  <pre><code>&lt;div class="cont"&gt;
      &lt;div id="bg-club" class="background club"&gt;&lt;/div&gt;
      &lt;div id="bg-cafe" class="background cafe active"&gt;&lt;/div&gt;
      &lt;div id="bg-fitness" class="background fitness"&gt;&lt;/div&gt;
      &lt;div id="bg-resto" class="background resto"&gt;&lt;/div&gt;
      &lt;div id="bg-lady" class="background lady"&gt;&lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>The CSS (for the sake of convenience the prefixed rules are removed):</p>
  
  <pre><code> .cont{
        position:absolute;
        top:0;
        right:0;
        bottom:0;
        left:0;
        z-index:1;
        overflow:hidden;
  
        perspective:1000px;
        transform-style:preserve-3d;
   }
   .background.active{
        visibility:visible;
        z-index:1;
   }
   .background{
        position:absolute;
        top:50px;
        right:50px;
        bottom:50px;
        left:50px;
        z-index:10;
  
        backface-visibility: hidden; 
        transform: translate3d(0, 0, 0);
        transform-style: preserve-3d; 
  
        visibility:hidden;
        overflow:hidden;
  
        background-repeat:no-repeat;
        background-position:center center;
        background-size:cover;
       }
        .background.cafe{background-color:#987071;}
        .background.club{background-color:#a3367f}
        .background.fitness{background-color:#79728b;}
        .background.lady{background-color:#a6160e;}
        .background.resto{background-color:#712912;}
  .rotateRoomLeftOut {
      transform-origin: 100% 50%;
      animation: rotateRoomLeftOut 4s both ease;
  }
  .rotateRoomLeftIn {
      transform-origin: 0% 50%;
      animation: rotateRoomLeftIn 4s both ease;
  }
  
  @keyframes rotateRoomLeftOut {
      to { opacity: .3; transform: translateX(-100%) rotateY(90deg); }
  }
  @keyframes rotateRoomLeftIn {
      from { opacity: .3; transform: translateX(100%) rotateY(-90deg); }
  }
  </code></pre>
  
  <p>And here is <a href="http://jsfiddle.net/sss46/9/" rel="nofollow noreferrer">the fiddle</a>. By pressing 1-5 yellow boxes we activate the corresponging background animation. The <code>perspective</code> here is 1000px, so the <em>un</em>desired effect can be achieved by resizing the window.</p>
  
  <p>The other example is <a href="http://tympanus.net/Development/PageTransitions/" rel="nofollow noreferrer">this great set of page 3D transitions</a>. Just navigate to Rotate->Room->Room to Left or Right.</p>
  
  <hr>
  
  <p><strong>Edit</strong></p>
  
  <p>Seems that Firefox makes only those elements flicker, whose corresponding dimension (either <code>width</code> for <code>RotateY</code> or <code>height</code> for <code>rotateX</code>) is greater than the parent's <code>perspective</code>. I haven't yet figured out, why that happens, but the simplest and the most straightforward solution so far is setting the aforementioned perspective greater than the element's dimension. In my case, it would be <code>100vw</code> (or <code>100vmax</code> to cover both rotate dimensions) for FF 19+ or some other way. </p>
  
  <p>The updated snippet :</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>$(document).ready(function(){
   var generalEvtAffix = '.hotdot', bodyEl = $('body'), pageContents = $('.sidebar, .center-block'),
    tabsSel = $('.areas [data-toggle="tab"]');
    
   // Анимация фонов на главной
   var bgs = $('.background');
   $('.areas [data-toggle="tab"]').on('click'+generalEvtAffix, function(event){
    event.preventDefault();
    var thisLink = $(this);
    /* Если уже активен или анимация всё ещё не закончена, ничего не делаем */
    if(thisLink.parent().hasClass('active') || bgs.hasClass('animated'))
     return;
    var bg = $('#bg-'+this.getAttribute('data-bg')),
     bgActive = $('.background.active');
    /* Случайным образом определяем направление анимации. */
    var animationDirs = ["Left"/* , "Top", "Right", "Bottom" */],
     animationDirection = animationDirs[Math.floor(Math.random() * (animationDirs.length) + 0)];
     
    /* - отключаем клик по ссылке на направлении - чтобы временно заблокировать переключение вкладок */
    tabsSel.on('click'+generalEvtAffix+'.clicked', function(e){
     e.preventDefault();
     return false;
    });
    
    bgActive.addClass('animated rotateRoom'+animationDirection+'Out')
     .on('animationend.homepage-area-click webkitAnimationEnd.homepage-area-click', function(){
      /* По окончании анимации "Прочь" прошлого активного элемента скрываем его */
      $(this).removeClass('animated active rotateRoom'+animationDirection+'Out')
       .off('animationend.homepage-area-click webkitAnimationEnd.homepage-area-click');
     });
    bg.addClass('animated active rotateRoom'+animationDirection+'In')
     .on('animationend.homepage-area-click webkitAnimationEnd.homepage-area-click', function(event){
      /* По окончании анимации обратно включаем клик. */
      console.log(event);
      $(this).removeClass('animated rotateRoom'+animationDirection+'In')
       .off('animationend.homepage-area-click webkitAnimationEnd.homepage-area-click');;
      tabsSel.off('click'+generalEvtAffix+'.clicked');
     });
   });
   });</code></pre>
  <pre class="snippet-code-css lang-css prettyprint-override"><code> .cont{
   position:absolute;
   top:0;
   right:0;
   bottom:0;
   left:0;
   z-index:1;
   overflow:hidden;
   
   -webkit-perspective:1000px;
   -moz-perspective:1000px;
   perspective:1000px;
   -webkit-transform-style:preserve-3d;
   -moz-transform-style:preserve-3d;
   transform-style:preserve-3d;
  }
  @-moz-document url-prefix(){
      .cont{
       perspective:100vw;   
      }
  }
  .background.active{
   visibility:visible;
   z-index:1;
  }
  .background{
   position:absolute;
   top:50px;
   right:50px;
   bottom:50px;
   left:50px;
      z-index:10;
   
    -webkit-backface-visibility: hidden;
   -moz-backface-visibility: hidden;
   backface-visibility: hidden; 
      -webkit-transform: translate3d(0, 0, 0);
      -moz-transform: translate3d(0, 0, 0);
      transform: translate3d(0, 0, 0);
    -webkit-transform-style: preserve-3d;
   -moz-transform-style: preserve-3d;
   transform-style: preserve-3d; 
   
   visibility:hidden;
    overflow:hidden;
   
   background-repeat:no-repeat;
   background-position:center center;
   background-size:cover;
  }
   .background.cafe{
    background-color:#987071;
      }
      .background.club{
    background-color:#a3367f
   }
   .background.fitness{
    background-color:#79728b;
   }
   .background.lady{
    background-color:#a6160e;
   }
   .background.resto{
    background-color:#712912;
   }
  /* Классы анимации фона типа "Room" */
   .rotateRoomLeftOut {
    -webkit-transform-origin: 100% 50%;
    -webkit-animation: rotateRoomLeftOut 4s both ease;
    -moz-transform-origin: 100% 50%;
    -moz-animation: rotateRoomLeftOut 4s both ease;
    transform-origin: 100% 50%;
    animation: rotateRoomLeftOut 4s both ease;
   }
   .rotateRoomLeftIn {
    -webkit-transform-origin: 0% 50%;
    -webkit-animation: rotateRoomLeftIn 4s both ease;
    -moz-transform-origin: 0% 50%;
    -moz-animation: rotateRoomLeftIn 4s both ease;
    transform-origin: 0% 50%;
    animation: rotateRoomLeftIn 4s both ease;
   }
  /* Описание анимаций */
  
   @-webkit-keyframes rotateRoomLeftOut {
    to { opacity: .3; -webkit-transform: translateX(-100%) rotateY(90deg); }
   }
   @-moz-keyframes rotateRoomLeftOut {
    to { opacity: .3; -moz-transform: translateX(-100%) rotateY(90deg); }
   }
   @keyframes rotateRoomLeftOut {
    to { opacity: .3; transform: translateX(-100%) rotateY(90deg); }
   }
  
   @-webkit-keyframes rotateRoomLeftIn {
    from { opacity: .3; -webkit-transform: translateX(100%) rotateY(-90deg); }
   }
   @-moz-keyframes rotateRoomLeftIn {
    from { opacity: .3; -moz-transform: translateX(100%) rotateY(-90deg); }
   }
   @keyframes rotateRoomLeftIn {
    from { opacity: .3; transform: translateX(100%) rotateY(-90deg); }
   }
  .areas{
      list-style:none;
      position:relative;z-index:1000;
  }
  .areas li a{
      display:block;
      width:20px;
      height:20px;
      background:yellow;
      margin:5px;
      color:black;
      
  }</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"&gt;&lt;/script&gt;
  &lt;div class="cont"&gt;
    &lt;div id="bg-club" class="background club"&gt;&lt;/div&gt;
    &lt;div id="bg-cafe" class="background cafe active"&gt;&lt;/div&gt;
    &lt;div id="bg-fitness" class="background fitness"&gt;&lt;/div&gt;
    &lt;div id="bg-resto" class="background resto"&gt;&lt;/div&gt;
    &lt;div id="bg-lady" class="background lady"&gt;&lt;/div&gt;
   &lt;/div&gt;
  
  &lt;ul class="areas text-center content-section"&gt;
    &lt;li&gt;&lt;a href="#club" class="club" data-target="[data-tab='club']" data-bg="club" data-toggle="tab"&gt;1&lt;/a&gt;
    &lt;/li&gt;&lt;li class="active"&gt;&lt;a href="#cafe" class="cafe" data-target="[data-tab='cafe']" data-bg="cafe" data-toggle="tab"&gt;2&lt;/a&gt;
    &lt;/li&gt;&lt;li&gt;&lt;a href="#fitness" class="fitness" data-target="[data-tab='fitness']" data-bg="fitness" data-toggle="tab"&gt;3&lt;/a&gt;
    &lt;/li&gt;&lt;li&gt;&lt;a href="#resto" class="resto" data-target="[data-tab='resto']" data-bg="resto" data-toggle="tab"&gt;4&lt;/a&gt;
    &lt;/li&gt;&lt;li&gt;&lt;a href="#lady" class="lady" data-target="[data-tab='lady']" data-bg="lady" data-toggle="tab"&gt;5&lt;/a&gt;
    &lt;/li&gt;
   &lt;/ul&gt;</code></pre>
  </div>
  </div>
  </p>
  
  <p>Still looking forward for a reason behind this behavior.</p>