<div id="container">
<div id="square" class="square">
<h4 class="v v1">1</h4>
<h4 class="v v2">2</h4>
<h4 class="v v3">3</h4>
<h4 class="v v4">4</h4>
</div>
<div id="square2" class="square">
<h4 class="v v1">1</h4>
<h4 class="v v2">2</h4>
<h4 class="v v3">3</h4>
<h4 class="v v4">4</h4>
</div>
</div>
<div id="scrollElement"></div>
body {
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
}
#container {
position:fixed;
top:0;
left:0;
width: 100%;
height:100%;
transform-style: preserve-3d;
perspective: 1000px;
display: flex;
justify-content: center;
align-items: center;
}
#square, #square2 {
width: 200px;
height: 200px;
background: red;
position:relative;
margin:120px;
transform-style: preserve-3d;
}
.square h4 {
margin:0;
color:#000;
font-size:30px;
font-weight: bold;
background: #FFF;
padding:3px;
width:40px;
height:40px;
border-radius: 5px;
border: 2px solid #000;
text-align: center;
}
.v {
position:absolute;
}
.v1 {
top:10px;
left:10px;
}
.v2 {
top:10px;
right:10px;
}
.v3 {
bottom:10px;
right:10px;
}
.v4 {
bottom:10px;
left:10px;
}
#scrollElement {
height: 10000px;
width: 100vw;
}
gsap.registerPlugin(ScrollTrigger);
const tl = gsap.timeline();
ScrollTrigger.create({
animation: tl,
trigger: "#scrollElement",
start: "top top",
end: "100% 100%",
scrub: 0.2
});
// Square on the left:
// 1 - tilt on X Axis
// 2 - tilt on Y Axis
// Result: Y axis won't coincide with the square Y axis, ( yellow )
tl.to("#square", { rotationX: 60, ease: "circ.out", duration: 5 })
.to("#square", { rotationY: 90, ease: "circ.out", duration: 5 })
.to("#square2", { rotationY: 60, ease: "circ.out", duration: 5 }, 0)
.to("#square2", { rotationX: 90, ease: "circ.out", duration: 5 }, ">");
// Square on the right:
// 1 - tilt on Y Axis
// 2 - tilt on X Axis
// Result: X axis now coincides with the square Y axis, ( green ) but it keeps being the document Y axis
////////////////////////////////////////
const elems = document.querySelectorAll(".square");
elems.forEach((el) => {
const { width, height } = el.getBoundingClientRect();
console.log(width, height);
const axes = {
x: {
rotate: "rotateZ(90deg)",
rotatePerp: "rotateZ(90deg) rotateY(90deg)",
top: "50%",
left: "50%",
translate: `translate(0, -${height}px)`,
translatePerp: `translate3d(0px, -${height}px, -${height}px)`,
color: "green"
},
y: {
rotate: "",
rotatePerp: "rotateY(90deg)",
top: "50%",
left: "50%",
translate: `translate(0, -${height}px)`,
color: "yellow"
},
z: {
rotate: "rotateZ(90deg) rotateX(90deg)",
rotatePerp: "rotateX(90deg)",
top: "50%",
left: "50%",
translate: `translate(0px, -${height}px)`,
color: "blue"
}
};
for (const key in axes) {
const axis = axes[key];
const div = document.createElement("div");
const div1 = document.createElement("div");
div.id = key;
div.style.transform = axis.translate + " " + axis.rotate;
div.style.top = axis.top;
div.style.left = axis.left;
div.style.backgroundColor = axis.color;
div.style.width = "5px";
div.style.height = height * 2 + "px";
div.style.position = "absolute";
div.innerHTML = `<h4>${key}</h4>`;
// Perpendicular axis
div1.id = key + "_" + "perp";
div1.style.transform = axis.translate + " " + axis.rotatePerp;
div1.style.top = axis.top;
div1.style.left = axis.left;
div1.style.backgroundColor = axis.color;
div1.style.width = "5px";
div1.style.height = height * 2 + "px";
div1.style.position = "absolute";
div1.innerHTML = `<h4>${key}</h4>`;
el.appendChild(div);
el.appendChild(div1);
}
});
This Pen doesn't use any external CSS resources.