As you can see under codepen.io, I’ve built a perspective view of a 3D cube (orange) in a 3D structure with CSS.
:root {
--side: 40px;
--rowCols: 3;
--wh: 121px;
--mside: -40px;
--twoSides: -80px;
}
body {
background-color: blue;
}
.canvas {
position: absolute;
left: 0px;
top: 10px;
transform-style: preserve3d;
perspective: 850px;
}
.grid {
position: absolute;
left: 200px;
top: 75px;
transform-style: preserve-3d;
animation: spin 15s infinite linear;
}
.grid .face {
position: absolute;
height: var(--wh);
width: var(--wh);
margin: 0;
background-image: repeating-linear-gradient(#ccc 0 1px, transparent 1px 100%),
repeating-linear-gradient(90deg, #ccc 0 1px, transparent 1px 100%);
background-size: var(--side) var(--side);
}
.cube {
left: 200px;
top: 75px;
position: absolute;
width: calc(var(--side) + 1);
height: calc(var(--side) + 1);
transform-style: preserve-3d;
/*transform: translateZ(var(--side));*/
animation: spin 15s infinite linear;
}
.cube .cface {
width: var(--side);
height: var(--side);
position: absolute;
border: 1px solid black;
display: flex;
background-color: rgb(238, 141, 14);
}
.cube .cface:nth-child(1) {
transform: translateZ(var(--side));
}
.cube .cface:nth-child(2) {
transform-origin: center right;
transform: rotateY(90deg);
}
.cube .cface:nth-child(3) {
transform-origin: center left;
transform: rotateY(-90deg);
}
.cube .cface:nth-child(4) {
transform-origin: top center;
transform: rotateX(90deg);
}
.cube .cface:nth-child(5) {
transform-origin: top center;
transform: rotateX(90deg) translateZ(var(--mSides));
}
@keyframes spin {
from {
transform: rotate3d(1, 1, 0, 0deg);
}
to {
transform: rotate3d(1, 1, 0, 360deg);
}
}
I managed to build it dynamically using the JS function setValues() where « side » is the side width (in px units) of the orange cube and « rowsCols » being the number of cubes per side. I would like to place the orange cube in the defined structure but I didn’t find how to move in all 3D axes by one unit. Does someone have an idea how to do it?
Code demo:
setValues(40, 3)
function setValues(side, rowsCols) {
let r = document.querySelector(':root')
r.style.setProperty('--side', `${side}px`)
r.style.setProperty('--rowCols', `${rowsCols}`)
r.style.setProperty('--wh', `${side * rowsCols + 1}px`)
r.style.setProperty('--mside', `-${side}px`)
r.style.setProperty('--twoSides', `-${side * 2}px`)
let str = ""
let max = (rowsCols + 1) * 2
for (let n = 0; n < max; n++) {
str = `${str}<div class="face"></div>\n`
}
//console.log(str)
document.getElementById("grid").innerHTML = str
str = ""
let pix = side
let f = 1
for (; f <= rowsCols; f++) {
str = `${str}.grid .face:nth-child(${f}){transform: translateZ(${pix}px);}\n`
pix += side
}
pix = 0
for (; f < max; f++) {
str = `${str}.grid .face:nth-child(${f}){transform-origin: center right; transform: rotateY(90deg) translateZ(${pix}px);}\n`
pix -= side
}
//console.log(str)
document.getElementById("style").innerHTML = str
}
:root {
--side: 40px;
--rowCols: 3;
--wh: 121px;
--mside: -40px;
--twoSides: -80px;
}
body {
background-color: blue;
}
.canvas {
position: absolute;
left: 0px;
top: 10px;
transform-style: preserve3d;
perspective: 850px;
}
.grid {
position: absolute;
left: 200px;
top: 75px;
transform-style: preserve-3d;
animation: spin 15s infinite linear;
}
.grid .face {
position: absolute;
height: var(--wh);
width: var(--wh);
margin: 0;
background-image: repeating-linear-gradient(#ccc 0 1px, transparent 1px 100%), repeating-linear-gradient(90deg, #ccc 0 1px, transparent 1px 100%);
background-size: var(--side) var(--side);
}
.cube {
left: 200px;
top: 75px;
position: absolute;
width: calc(var(--side) + 1);
height: calc(var(--side) + 1);
transform-style: preserve-3d;
/*transform: translateZ(var(--side));*/
animation: spin 15s infinite linear;
}
.cube .cface {
width: var(--side);
height: var(--side);
position: absolute;
border: 1px solid black;
display: flex;
background-color: rgb(238, 141, 14);
}
.cube .cface:nth-child(1) {
transform: translateZ(var(--side));
}
.cube .cface:nth-child(2) {
transform-origin: center right;
transform: rotateY(90deg);
}
.cube .cface:nth-child(3) {
transform-origin: center left;
transform: rotateY(-90deg);
}
.cube .cface:nth-child(4) {
transform-origin: top center;
transform: rotateX(90deg);
}
.cube .cface:nth-child(5) {
transform-origin: top center;
transform: rotateX(90deg) translateZ(var(--mSides));
}
@keyframes spin {
from {
transform: rotate3d(1, 1, 0, 0deg);
}
to {
transform: rotate3d(1, 1, 0, 360deg);
}
}
<style id="style"></style>
<div class="canvas">
<div class="grid" id="grid">
<div class="face"></div>
</div>
<div class="cube">
<div class="cface"></div>
<div class="cface"></div>
<div class="cface"></div>
<div class="cface"></div>
<div class="cface"></div>
<div class="cface"></div>
</div>
</div>
After a while, I found the way to have the orange cube being part of the grid structure or better said class. I modified a bit HTML, CSS and JS. The new version is available in codepen.io V2.
To finalize what I wanted to build, I added a new (JS) function which updates the CSS for displaying the small (orange) cube of size [pix] pixels at a given [x, y, z] location. I did all this in order to show the current location in a 3D square maze of side [side].