Home > OS >  Why, when I switch from @property values to var values, does my CSS animation misbehave?
Why, when I switch from @property values to var values, does my CSS animation misbehave?

Time:11-10

I've been working on expanding my CSS knowledge, and made a simple demo of 3d transformations, showing a set of squares rotating in 3d on a plane.

I initially wrote it using @property definitions of the rotation angles, and later realised I could do it with simple var definitions. When I change it though, the squares, which should stay a consistent distance apart, start flattening together in the animation cycle. I don't see why it does this and am hoping someone can point me in the right direction.

Here it is working. Note that Firefox doesn't handle @property functions (hence the need to change it)

:root{
        --cubeSize: 32vw;
}

* { margin: 0; padding: 0;}

body, html{
        height: 100%;
        width: 100%;
        overflow: hidden;
}

body{
        display: flex;
        justify-content: center; 
        align-items: center;    
        height: 100%;
}

* {
        perspective: 70vw;
        transform-style: preserve-3d; 
}

#boxContainer {
        display: flex;
        justify-content: center; 
        align-items: center;    
        width: 0;
        height: 0;
        position: relative;
        transform: translateZ(-50vw);
}

#boxContainer > *:nth-child(1){
        background-color: #f00;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : -16vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

#boxContainer > *:nth-child(2){
        background-color: #f40;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : -12vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

#boxContainer > *:nth-child(3){
        background-color: #ff0;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : -8vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

#boxContainer > *:nth-child(4){
        background-color: #8f0;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : -4vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

#boxContainer > *:nth-child(5){
        background-color: #0f0;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : 0;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

#boxContainer > *:nth-child(6){
        background-color: #0f8;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : 4vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

#boxContainer > *:nth-child(7){
        background-color: #0ff;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : 8vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}


#boxContainer > *:nth-child(8){
        background-color: #66f;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : 12vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

#boxContainer > *:nth-child(9){
        background-color: #f0f;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : 16vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

@property --animAngY {
        syntax : '<angle>';
        initial-value: 0deg;
        inherits: false;
}

@property --animAngX {
        syntax : '<angle>';
        initial-value: 0deg;
        inherits: false;
}

@property --animAngZ {
        syntax : '<angle>';
        initial-value: 0deg;
        inherits: false;
}

#boxContainer > * {
        --gridColour: #0005;
        --spacing: 5mm;
        background-image:
                repeating-linear-gradient(90deg, var(--gridColour) 0px, var(--gridColour) 1px, #fff0 0px, #fff0 var(--spacing)),
                repeating-linear-gradient(0deg, var(--gridColour) 0px, var(--gridColour) 1px,  #fff0 0px, #fff0 var(--spacing))
        ;
        position: absolute;
        opacity: 1;
        display: inline-block;
        width: var(--cubeSize);
        height: var(--cubeSize);
        display: inline-block;
        transform-origin: 50% 50%;
        transform:
                rotateX( 
                        calc(var(--Xangle)   var(--animAngX))
                ) 
                rotateY( 
                        calc(var(--Yangle)   var(--animAngY))
                ) 
                rotateZ( 
                        calc(var(--Zangle)   var(--animAngZ))
                ) 
                translateX(
                        var(--Xoffset)
                ) 
                translateY(
                        var(--Yoffset)
                ) 
                translateZ(
                        var(--Zoffset)
                ) 
        ;
        animation-name: cubeSpin;
        animation-duration: 10s;
        animation-iteration-count: infinite;
        animation-timing-function: linear;
}

@keyframes cubeSpin {
        to {
                --animAngX : 1080deg;
                --animAngY : 360deg;
                --animAngZ : 720deg; 
        }
}

#floor{
        --gridColour : #8af;
        --bgColour: #0000;
        --spacing: 10vw;
        --zPos: -10vw;
        --lineWidth: 0.25vw;

        position: absolute;
        display: inline-block;
        width: 500vw;
        height: 500vw;
        background-color: #000;
        border-radius: 50%;

        background-image:
                repeating-linear-gradient(
                        90deg, 
                        var(--gridColour) 0vw, 
                        var(--gridColour) var(--lineWidth), 
                        var(--bgColour) var(--lineWidth), 
                        var(--bgColour) var(--spacing)
                ),
                repeating-linear-gradient(
                        0deg, 
                        var(--gridColour) 0vw, 
                        var(--gridColour) var(--lineWidth), 
                        var(--bgColour) var(--lineWidth), 
                        var(--bgColour) var(--spacing)
                )
        ;

        transform: rotateX(90deg) rotateZ(0deg) translateZ(var(--zPos));

        animation-name: floorSpin;
        animation-duration: 10s;
        animation-iteration-count: infinite;
        animation-timing-function: linear;

}

@keyframes floorSpin {
        to {
                transform: rotateX(90deg) rotateZ(360deg) translateZ(var(--zPos));
        }
}



body{
        background-image: linear-gradient( black 0, #1a0450 25%, #1e8ad9 56% );
}
<body>
        <div id="floor"></div>
        <div id="boxContainer">
                <div></div>
                <div></div>
                <div></div>
                <div></div>
                <div></div>
                <div></div>
                <div></div>
                <div></div>
                <div></div>
        </div>
</body>

If I replace this part:

@keyframes cubeSpin {
        to {
                --animAngX : 1080deg;
                --animAngY : 360deg;
                --animAngZ : 720deg;
        }
}  

With this:

@keyframes cubeSpin {
        to {
                transform:
                        rotateX(
                                calc(var(--Xangle)   1080deg)
                        )
                        rotateY(
                                calc(var(--Yangle)   360deg)
                        )
                        rotateZ(
                                calc(var(--Zangle)   720deg)
                        )
                        
        }
}      

Then this is the outcome

:root{
        --cubeSize: 32vw;
}

* { margin: 0; padding: 0;}

body, html{
        height: 100%;
        width: 100%;
        overflow: hidden;
}

body{
        display: flex;
        justify-content: center; 
        align-items: center;    
        height: 100%;
}

* {
        perspective: 70vw;
        transform-style: preserve-3d; 
}

#boxContainer {
        display: flex;
        justify-content: center; 
        align-items: center;    
        width: 0;
        height: 0;
        position: relative;
        transform: translateZ(-50vw);
}

#boxContainer > *:nth-child(1){
        background-color: #f00;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : -16vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

#boxContainer > *:nth-child(2){
        background-color: #f40;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : -12vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

#boxContainer > *:nth-child(3){
        background-color: #ff0;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : -8vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

#boxContainer > *:nth-child(4){
        background-color: #8f0;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : -4vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

#boxContainer > *:nth-child(5){
        background-color: #0f0;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : 0;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

#boxContainer > *:nth-child(6){
        background-color: #0f8;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : 4vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

#boxContainer > *:nth-child(7){
        background-color: #0ff;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : 8vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}


#boxContainer > *:nth-child(8){
        background-color: #66f;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : 12vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

#boxContainer > *:nth-child(9){
        background-color: #f0f;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : 16vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

@property --animAngY {
        syntax : '<angle>';
        initial-value: 0deg;
        inherits: false;
}

@property --animAngX {
        syntax : '<angle>';
        initial-value: 0deg;
        inherits: false;
}

@property --animAngZ {
        syntax : '<angle>';
        initial-value: 0deg;
        inherits: false;
}

#boxContainer > * {
        --gridColour: #0005;
        --spacing: 5mm;
        background-image:
                repeating-linear-gradient(90deg, var(--gridColour) 0px, var(--gridColour) 1px, #fff0 0px, #fff0 var(--spacing)),
                repeating-linear-gradient(0deg, var(--gridColour) 0px, var(--gridColour) 1px,  #fff0 0px, #fff0 var(--spacing))
        ;
        position: absolute;
        opacity: 1;
        display: inline-block;
        width: var(--cubeSize);
        height: var(--cubeSize);
        display: inline-block;
        transform-origin: 50% 50%;
        transform:
                rotateX( 
                        calc(var(--Xangle)   var(--animAngX))
                ) 
                rotateY( 
                        calc(var(--Yangle)   var(--animAngY))
                ) 
                rotateZ( 
                        calc(var(--Zangle)   var(--animAngZ))
                ) 
                translateX(
                        var(--Xoffset)
                ) 
                translateY(
                        var(--Yoffset)
                ) 
                translateZ(
                        var(--Zoffset)
                ) 
        ;
        animation-name: cubeSpin;
        animation-duration: 10s;
        animation-iteration-count: infinite;
        animation-timing-function: linear;
}

@keyframes cubeSpin {
        to {
            transform:
                    rotateX(
                            calc(var(--Xangle)   1080deg)
                    )
                    rotateY(
                            calc(var(--Yangle)   360deg)
                    )
                    rotateZ(
                            calc(var(--Zangle)   720deg)
                    )
        }
}

#floor{
        --gridColour : #8af;
        --bgColour: #0000;
        --spacing: 10vw;
        --zPos: -10vw;
        --lineWidth: 0.25vw;

        position: absolute;
        display: inline-block;
        width: 500vw;
        height: 500vw;
        background-color: #000;
        border-radius: 50%;

        background-image:
                repeating-linear-gradient(
                        90deg, 
                        var(--gridColour) 0vw, 
                        var(--gridColour) var(--lineWidth), 
                        var(--bgColour) var(--lineWidth), 
                        var(--bgColour) var(--spacing)
                ),
                repeating-linear-gradient(
                        0deg, 
                        var(--gridColour) 0vw, 
                        var(--gridColour) var(--lineWidth), 
                        var(--bgColour) var(--lineWidth), 
                        var(--bgColour) var(--spacing)
                )
        ;

        transform: rotateX(90deg) rotateZ(0deg) translateZ(var(--zPos));

        animation-name: floorSpin;
        animation-duration: 10s;
        animation-iteration-count: infinite;
        animation-timing-function: linear;

}

@keyframes floorSpin {
        to {
                transform: rotateX(90deg) rotateZ(360deg) translateZ(var(--zPos));
        }
}



body{
        background-image: linear-gradient( black 0, #1a0450 25%, #1e8ad9 56% );
}
<body>
        <div id="floor"></div>
        <div id="boxContainer">
                <div></div>
                <div></div>
                <div></div>
                <div></div>
                <div></div>
                <div></div>
                <div></div>
                <div></div>
                <div></div>
        </div>
</body>

As you can see in those demos, the first one works as I expect, and in the second, the rotating planes collapse together throughout the entire animation

Edit:

To expand a bit on what it does:

  • The bottom grid is just a div that's spinning, it works fine and is indeed using the more widely supported CSS changes in the animation.

  • In the middle of the screen is a single div with no width or height, it contains the nine divs that are the rotating layers

  • The layers themselves are being rotated, not the parent div as - if I understand correctly - rotating the parent div will render those children as being projected on to the parent's plane.

  • All of the layers are being transformed by the same animation "cubeSpin", as that is tied to all childen of the div #boxContainer.

CodePudding user response:

You are missing the translate part of the transform

transform:
   rotateX(
     calc(var(--Xangle)   1080deg)
   )
   rotateY(
     calc(var(--Yangle)   360deg)
   )
   rotateZ(
     calc(var(--Zangle)   720deg)
   )
   translateX(
     var(--Xoffset)
   ) 
   translateY(
     var(--Yoffset)
   ) 
   translateZ(
     var(--Zoffset)
   ) 

:root{
        --cubeSize: 32vw;
}

* { margin: 0; padding: 0;}

body, html{
        height: 100%;
        width: 100%;
        overflow: hidden;
}

body{
        display: flex;
        justify-content: center; 
        align-items: center;    
        height: 100%;
}

* {
        perspective: 70vw;
        transform-style: preserve-3d; 
}

#boxContainer {
        display: flex;
        justify-content: center; 
        align-items: center;    
        width: 0;
        height: 0;
        position: relative;
        transform: translateZ(-50vw);
}

#boxContainer > *:nth-child(1){
        background-color: #f00;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : -16vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

#boxContainer > *:nth-child(2){
        background-color: #f40;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : -12vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

#boxContainer > *:nth-child(3){
        background-color: #ff0;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : -8vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

#boxContainer > *:nth-child(4){
        background-color: #8f0;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : -4vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

#boxContainer > *:nth-child(5){
        background-color: #0f0;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : 0;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

#boxContainer > *:nth-child(6){
        background-color: #0f8;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : 4vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

#boxContainer > *:nth-child(7){
        background-color: #0ff;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : 8vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}


#boxContainer > *:nth-child(8){
        background-color: #66f;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : 12vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

#boxContainer > *:nth-child(9){
        background-color: #f0f;
        --Xoffset : 0cm;
        --Yoffset : 0cm;
        --Zoffset : 16vw;
        --Xangle : 0deg;
        --Yangle : 90deg;
        --Zangle : 0deg;
}

@property --animAngY {
        syntax : '<angle>';
        initial-value: 0deg;
        inherits: false;
}

@property --animAngX {
        syntax : '<angle>';
        initial-value: 0deg;
        inherits: false;
}

@property --animAngZ {
        syntax : '<angle>';
        initial-value: 0deg;
        inherits: false;
}

#boxContainer > * {
        --gridColour: #0005;
        --spacing: 5mm;
        background-image:
                repeating-linear-gradient(90deg, var(--gridColour) 0px, var(--gridColour) 1px, #fff0 0px, #fff0 var(--spacing)),
                repeating-linear-gradient(0deg, var(--gridColour) 0px, var(--gridColour) 1px,  #fff0 0px, #fff0 var(--spacing))
        ;
        position: absolute;
        opacity: 1;
        display: inline-block;
        width: var(--cubeSize);
        height: var(--cubeSize);
        display: inline-block;
        transform-origin: 50% 50%;
        transform:
                rotateX( 
                        calc(var(--Xangle)   var(--animAngX))
                ) 
                rotateY( 
                        calc(var(--Yangle)   var(--animAngY))
                ) 
                rotateZ( 
                        calc(var(--Zangle)   var(--animAngZ))
                ) 
                translateX(
                        var(--Xoffset)
                ) 
                translateY(
                        var(--Yoffset)
                ) 
                translateZ(
                        var(--Zoffset)
                ) 
        ;
        animation-name: cubeSpin;
        animation-duration: 10s;
        animation-iteration-count: infinite;
        animation-timing-function: linear;
}

@keyframes cubeSpin {
        to {
            transform:
                    rotateX(
                            calc(var(--Xangle)   1080deg)
                    )
                    rotateY(
                            calc(var(--Yangle)   360deg)
                    )
                    rotateZ(
                            calc(var(--Zangle)   720deg)
                    )
                translateX(
                        var(--Xoffset)
                ) 
                translateY(
                        var(--Yoffset)
                ) 
                translateZ(
                        var(--Zoffset)
                ) 
        }
}

#floor{
        --gridColour : #8af;
        --bgColour: #0000;
        --spacing: 10vw;
        --zPos: -10vw;
        --lineWidth: 0.25vw;

        position: absolute;
        display: inline-block;
        width: 500vw;
        height: 500vw;
        background-color: #000;
        border-radius: 50%;

        background-image:
                repeating-linear-gradient(
                        90deg, 
                        var(--gridColour) 0vw, 
                        var(--gridColour) var(--lineWidth), 
                        var(--bgColour) var(--lineWidth), 
                        var(--bgColour) var(--spacing)
                ),
                repeating-linear-gradient(
                        0deg, 
                        var(--gridColour) 0vw, 
                        var(--gridColour) var(--lineWidth), 
                        var(--bgColour) var(--lineWidth), 
                        var(--bgColour) var(--spacing)
                )
        ;

        transform: rotateX(90deg) rotateZ(0deg) translateZ(var(--zPos));

        animation-name: floorSpin;
        animation-duration: 10s;
        animation-iteration-count: infinite;
        animation-timing-function: linear;

}

@keyframes floorSpin {
        to {
                transform: rotateX(90deg) rotateZ(360deg) translateZ(var(--zPos));
        }
}



body{
        background-image: linear-gradient( black 0, #1a0450 25%, #1e8ad9 56% );
}
<body>
  <div id="floor"></div>
  <div id="boxContainer">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
  </div>
</body>

  • Related