Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSS Animation for transform does not work properly when using an initial keyframe with matrix3d value

I need to execute an animation on a div for properties scaleZ() and translateZ() using CSS Animations.

The following code works fine when initial and last keyframes values in the animation for transform property are in a similar "format":

  • 0% is transform: rotateY(-179deg) scaleZ(2) translateZ(200px);
  • 100% is transform: rotateY(179deg) scaleZ(2) translateZ(200px);

        console.clear();
        document.addEventListener('DOMContentLoaded', () => {
            let content1 = document.querySelector('#content1');
            var computedTransform = window.getComputedStyle(content1).transform;
            console.log(computedTransform);

        });
        @-webkit-keyframes animation {
            0% {
                /*works*/
                -webkit-transform: rotateY(-179deg) scaleZ(2) translateZ(200px);
                        transform: rotateY(-179deg) scaleZ(2) translateZ(200px);
                /*issue*/
                /*transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1);*/
            }


            100% {
                -webkit-transform: rotateY(179deg) scaleZ(2) translateZ(200px);
                        transform: rotateY(179deg) scaleZ(2) translateZ(200px);
            }
        }

        @keyframes animation {
            0% {
                /*works*/
                -webkit-transform: rotateY(-179deg) scaleZ(2) translateZ(200px);
                        transform: rotateY(-179deg) scaleZ(2) translateZ(200px);
                /*issue*/
                /*transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1);*/
            }


            100% {
                -webkit-transform: rotateY(179deg) scaleZ(2) translateZ(200px);
                        transform: rotateY(179deg) scaleZ(2) translateZ(200px);
            }
        }

        #content1 {
            -webkit-animation: animation 2s;
                    animation: animation 2s;
            -webkit-animation-fill-mode: forwards;
                    animation-fill-mode: forwards;
            /*works*/
            -webkit-transform: rotateY(-179deg) scaleZ(2) translateZ(200px);
                    transform: rotateY(-179deg) scaleZ(2) translateZ(200px);
            /*issue*/
            /*transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1);*/
        }
    <div id="wrapper1" style="position:fixed; top: 100px; left:300px; perspective: 1000px; width: 250px; height:250px; border: dotted 1px blue">
        <div id="content1" style="width: 250px; height:250px; background-color:lightsalmon; opacity:0.2;">
        </div>
    </div>

The same animation with transform for key-frame 0% written as matrix3D returned from Window.getComputedStyle() does not make the animation work properly:

  • 0% is transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1);
  • 100% is transform: rotateY(179deg) scaleZ(2) translateZ(200px);

        console.clear();
        document.addEventListener('DOMContentLoaded', () => {
            let content1 = document.querySelector('#content1');
            var computedTransform = window.getComputedStyle(content1).transform;
            console.log(computedTransform);

        });
 @-webkit-keyframes animation {
            0% {
                /*works*/
                /*transform: rotateY(-179deg) scaleZ(2) translateZ(200px);*/
                /*issue*/
                -webkit-transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1);
                        transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1);
            }


            100% {
                -webkit-transform: rotateY(179deg) scaleZ(2) translateZ(200px);
                        transform: rotateY(179deg) scaleZ(2) translateZ(200px);
            }
        }

        @keyframes animation {
            0% {
                /*works*/
                /*transform: rotateY(-179deg) scaleZ(2) translateZ(200px);*/
                /*issue*/
                -webkit-transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1);
                        transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1);
            }


            100% {
                -webkit-transform: rotateY(179deg) scaleZ(2) translateZ(200px);
                        transform: rotateY(179deg) scaleZ(2) translateZ(200px);
            }
        }

        #content1 {
            -webkit-animation: animation 2s;
                    animation: animation 2s;
            -webkit-animation-fill-mode: forwards;
                    animation-fill-mode: forwards;
            /*works*/
            /*transform: rotateY(-179deg) scaleZ(2) translateZ(200px);*/
            /*issue*/
            -webkit-transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1);
                    transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1);
        }
    <div id="wrapper1" style="position:fixed; top: 100px; left:300px; perspective: 1000px; width: 250px; height:250px; border: dotted 1px blue">
        <div id="content1" style="width: 250px; height:250px; background-color:lightsalmon; opacity:0.2;">
        </div>
    </div>

For technical reasons I need to use as key-frame 0% a value for transformation properly returned from a computed style in the DOM, using Window.getComputedStyle() or another function if available.

My questions:

  1. Is my code for the second example buggy?
  2. Could you suggest an alternative way to get the computed value from the DOM?
  3. Do you know of any bugs related to value returned from Window.getComputedStyle()?
  4. Do you know of any bugs with CSS Animations and different "notation" for transform?

Notes: I see this issue on latest Chrome (55.0.2883.87 m) and FireFox (50.1.0).

Any solutions or ideas is welcome.


EDIT:

I have created few new examples (for Chrome) for further investigation.

Basically the two example rotate

from rotateY(20deg) to rotateY(90deg)

Using transform with one type of "notation", works as expected

Desired effect https://jsbin.com/bodaxefake/edit?html,output

When the values are instead taken by a computed CSS style and reapplied to the animation using matrix3d, the animation has a slight distortion.

Instead I would expect to reproduce the animation which exactly the same result, as for my understanding the matrix3d from Window.getComputedStyle() should return the same value.

Incorrect effect https://jsbin.com/luhikahexi/edit?html,output

like image 821
GibboK Avatar asked Jan 11 '17 11:01

GibboK


People also ask

How does keyframe animation work CSS?

Each keyframe describes how the animated element should render at a given time during the animation sequence. Since the timing of the animation is defined in the CSS style that configures the animation, keyframes use a <percentage> to indicate the time during the animation sequence at which they take place.

Which CSS animation property specifies the element style when the animation is not taking place?

The animation-fill-mode property specifies a style for the element when the animation is not playing (before it starts, after it ends, or both).

Which is the correct way to declare keyframes for animation?

To use keyframes, create a @keyframes rule with a name that is then used by the animation-name property to match an animation to its keyframe declaration.


1 Answers

Your problem is point number 4. But it isn't really a bug, it 's a complex algorithm trying to figure out what do you want to do.

When you make an animation move from rotate(0deg) to rotate(360deg), have you ever wondered that the 2 matrices are just the same ? If only the initial an final states are specified, the animation would not exist.

When you set the animation the way you did, the algorithm is clueless about what to do, and so the behaviour is not what you expect. But I wouldn't say this is a bug.

I have set an animation that does what you want. The trick is to leave the matrix constant, add an initial rotation that is what we will change, and just add another rotation opposite to this one to keep the original state.

Since this snippet is a little bit extense, I have removed webkit prefixes. (on the other hand, nor really needed nowadays)

console.clear();
document.addEventListener('DOMContentLoaded', () => {
  let content1 = document.querySelector('#content1');
  var computedTransform = window.getComputedStyle(content1).transform;
  console.log(computedTransform);

});
@keyframes animation {
  0% {
    transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1);
  }
    0.1% {
    transform: rotateY(-179deg) rotateY(179deg) matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1);
  }
  100% {
    transform: rotateY(179deg) rotateY(179deg) matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1);
  }
}
#content1 {
  animation: animation 2s;
  animation-fill-mode: forwards;
  transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1);
}
<div id="wrapper1" style="position:fixed; top: 100px; left:300px; perspective: 1000px; width: 250px; height:250px; border: dotted 1px blue">
  <div id="content1" style="width: 250px; height:250px; background-color:lightsalmon; opacity:0.2;">
  </div>
</div>

The real problem is that there is not enough information in the beginning and end point of an animation to reconstruct it. The matrices of the transforms don't have the information that you are giving in a series of individual transforms

See the snippet (in 2D): the begin and end states are the same, the animation isn't. In 3D, there are even more posibilities

.test {
  width: 50px;
  height: 50px;
  position: absolute;
  top: 400px;
  left: 100px;
}
#one {
  background-color: lightgreen;
  transform: translateX(200px);
  animation: tr1 6s infinite;
}
@keyframes tr1 {
  0% {
    transform: rotate(0deg) translateX(200px)
  }
  33%,
  100% {
    transform: rotate(-90deg) translateX(200px)
  }
}
#two {
  background-color: lightblue;
  transform: translate(200px, 0px);
  animation: tr2 6s infinite;
}
@keyframes tr2 {
  0%, 33% {
    transform: translate(200px, 0px) rotate(0deg)
  }
  66%,
  100% {
    transform: translate(0px, -200px) rotate(-90deg)
  }
}
#three {
  background-color: tomato;
  transform: translate(200px, -200px) rotate(0deg) translateY(200px);
  animation: tr3 6s infinite;
}
@keyframes tr3 {
  0%, 66% {
    transform: translate(200px, -200px) rotate(0deg) translateY(200px) rotate(0deg);
  }
  100% {
    transform:  translate(200px, -200px) rotate(-270deg)  translateY(200px) rotate(180deg);
  }
}
<div class="test" id="one">1</div>
<div class="test" id="two">2</div>
<div class="test" id="three">3</div>
like image 88
vals Avatar answered Oct 17 '22 07:10

vals