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>