svg.logo(xmlns="http://www.w3.org/2000/svg" width="100" height="40" viewBox="0 0 100 40")
path(fill="var(--c-ikea-blue)" fill-rule="evenodd" d="M99.9856687 40H0V0h100v40z")
path(fill="var(--c-ikea-yellow)" fill-rule="evenodd" d="M2 20c0 9.8325 20.1163 18 48.0072 18C77.898 38 98 29.8325 98 20S77.8837 2 50.0072 2C22.1306 2 2 10.1675 2 20z")
path(fill="var(--c-ikea-blue)" fill-rule="nonzero" d="M46.448 26.0047c.3153.4477.6593.8674 1.0606 1.2452H36.6874c0-.4198-.4156-1.2732-.8743-1.9447-.4586-.6716-2.9382-4.351-2.9382-4.351v5.0505c0 .4197 0 .8254.215 1.2452h-9.0152c.215-.4198.215-.8255.215-1.2452V14.0008c0-.4197 0-.8254-.215-1.2451h9.0152c-.215.4197-.215.8254-.215 1.2451v5.2465s2.8809-3.6655 3.5402-4.519c.5016-.6435 1.118-1.553 1.118-1.9726h9.4022c-.645.4197-1.3616 1.1752-1.9493 1.8747-.516.6156-3.4398 4.0992-3.4398 4.0992s4.3284 6.4497 4.9017 7.2751zm2.8378-12.0039v12.0039c0 .4197 0 .8254-.215 1.2452h17.3999v-4.0293c-.43.2098-.8457.2098-1.2756.2098h-7.324v-1.9027h7.0373v-3.05h-7.0373v-1.9166h7.324c.43 0 .8456 0 1.2756.1959v-4.0153H49.0708c.215.4337.215.8394.215 1.2591zm41.2924 12.0039c.1433.4617.387.8814.7023 1.2452h-9.4309c.043-.4198-.1146-.8255-.2866-1.2452 0 0-.1434-.3358-.344-.8254l-.086-.2099h-5.4321l-.086.2238s-.1577.4058-.301.8255c-.1433.4197-.301.8254-.2436 1.2451h-7.4387a3.6406 3.6406 0 0 0 .6737-1.2451l4.4574-12.0039c.1577-.4197.3153-.8254.258-1.2451h12.5697c-.1146.4197.1147.8254.2724 1.2451.3726.9094 4.4 11.1784 4.7154 11.9899zm-10.6348-4.0992-1.3186-3.3578c-.1147-.3077-.215-.6295-.2867-.9513a5.5011 5.5011 0 0 1-.258.9513c-.043.14-.602 1.609-1.247 3.3578h3.1103zm-60.1399-9.1498H10c.215.4197.215.8254.215 1.2451v12.0039c0 .4197 0 .8254-.215 1.2452h9.8035c-.215-.4198-.215-.8255-.215-1.2452V14.0008c0-.4197 0-.8254.215-1.2451zm67.7648 1.1472c-.043-1.0213.774-1.8747 1.8203-1.9027h.129c1.0606-.014 1.9349.7974 1.9492 1.8327v.07c.0287 1.0493-.817 1.9307-1.9062 1.9587-1.075.028-1.978-.7975-2.0066-1.8608.0143-.028.0143-.07.0143-.098zm.387 0c0 .8394.7023 1.525 1.5623 1.525s1.5622-.6856 1.5622-1.525c0-.8394-.7023-1.525-1.5622-1.525-.8313-.028-1.5336.6016-1.5623 1.413v.112zm1.1753 1.1332h-.344v-2.2944h.8743c.4157.014.731.3357.731.7415 0 .2798-.1577.5316-.4157.6715l.5017.8814h-.387l-.4587-.8114h-.5016v.8114zm0-1.1332h.473c.2293.014.43-.154.43-.3778 0-.2238-.1577-.4197-.387-.4197h-.516v.7975z")
div.kallax
div.kallax__control
div.kallax__unit
div.kallax__horizontals
div.kallax__horizontalTop
div.kallax__upper
div.kallax__screws
div.kallax__screw
div.kallax__screw
div.kallax__screw
div.kallax__screw
div.kallax__lower
div.kallax__sideLeft
div.kallax__sideRight
div.kallax__back
div.kallax__horizontalUpper
div.kallax__upper
div.kallax__lower
div.kallax__back
div.kallax__horizontalCenter
div.kallax__upper
div.kallax__lower
div.kallax__back
div.kallax__horizontalLower
div.kallax__upper
div.kallax__lower
div.kallax__back
div.kallax__horizontalBottom
div.kallax__upper
div.kallax__lower
div.kallax__screws
div.kallax__screw
div.kallax__screw
div.kallax__screw
div.kallax__screw
div.kallax__sideLeft
div.kallax__sideRight
div.kallax__back
div.kallax__verticals
div.kallax__verticalLeft
div.kallax__sideLeft
div.kallax__sideRight
div.kallax__back
div.kallax__verticalCenterLeft
div.kallax__sideLeft
div.kallax__sideRight
div.kallax__back
div.kallax__verticalCenter
div.kallax__sideLeft
div.kallax__sideRight
div.kallax__back
div.kallax__verticalCenterRight
div.kallax__sideLeft
div.kallax__sideRight
div.kallax__back
div.kallax__verticalRight
div.kallax__sideLeft
div.kallax__sideRight
div.kallax__back
fieldset
legend Colour
input(name="color" type="radio" value="white" id="white" checked)
label(for="white") White
input(name="color" type="radio" value="black-brown" id="black-brown")
label(for="black-brown") Black/Brown
input(name="color" type="radio" value="oak" id="oak")
label(for="oak") Oak
View Compiled
:root {
--c-ikea-blue: oklch(47% 0.15 255deg);
--c-ikea-yellow: oklch(89% 0.18 98deg);
}
body {
align-items: center;
background-color: var(--c-ikea-blue);
display: grid;
font-family: "Noto IKEA", "Noto Sans", "Roboto", "Open Sans", system-ui, sans-serif;
margin: 0;
min-block-size: 100dvh;
}
.logo {
block-size: 66%;
inline-size: 66%;
position: absolute;
inset: 33% auto auto 50%;
translate: -50% -50%;
}
.kallax {
container-type: inline-size;
display: grid;
perspective: 1000px;
place-content: center;
}
.kallax__control {
--m: min(0.4cqw, 0.4svh);
--total-height: 146.5;
--total-width: 147;
--total-depth: 39;
--outer-thickness: 4;
--inner-thickness: 1.5;
--storage-size: 33.5;
--screw-size: 1.5;
--c-screw: oklch(77% 0.007 116deg);
--c-white: oklch(97% 0.005 118deg);
--t-white: none;
--c-black-brown: oklch(30% 0.008 122deg);
--t-black-brown: none;
--c-oak: oklch(75% 0.05 80deg);
--t-oak: url("https://www.transparenttextures.com/patterns/purty-wood.png");
--kallax-color: var(--c-white);
--kallax-texture: var(--t-white);
block-size: calc(var(--total-height) * var(--m));
cursor: all-scroll;
inline-size: calc(var(--total-width) * var(--m));
transform-style: preserve-3d;
transform-origin: center center calc(((var(--total-depth) / 2) * var(--m)) * -1)
}
.kallax__unit {
block-size: 100%;
position: relative;
transform-style: preserve-3d;
}
.kallax__horizontals,
.kallax__verticals {
display: flex;
gap: calc(var(--storage-size) * var(--m));
transform-style: preserve-3d;
}
.kallax__horizontals {
flex-direction: column;
}
.kallax__verticals {
block-size: calc(var(--total-height) - (var(--outer-thickness) * 2) * var(--m));
inset-block: calc(var(--outer-thickness) * var(--m));
inset-inline: 50% auto;
position: absolute;
translate: -50% 0 calc(-0.2 * var(--m));
}
.kallax__horizontals > *,
.kallax__verticals > * {
background-color: var(--kallax-color);
background-image: var(--kallax-texture);
box-shadow: inset 0 0 calc(0.25 * var(--m)) 0 oklch(0% 0 0deg / 20%);
flex: 0 0 auto;
position: relative;
transform-style: preserve-3d;
}
.kallax__horizontals > * {
block-size: calc(var(--inner-thickness) * var(--m));
inline-size: calc((var(--total-width) - (var(--outer-thickness) * 2)) * var(--m));
margin-inline: auto;
}
.kallax__verticals > * {
block-size: calc(var(--total-height) - (var(--outer-thickness) * 2) * var(--m));
inline-size: calc(var(--inner-thickness) * var(--m));
}
.kallax__horizontalTop,
.kallax__horizontalBottom {
block-size: calc(var(--outer-thickness) * var(--m));
inline-size: calc(var(--total-width) * var(--m));
}
.kallax__verticalLeft,
.kallax__verticalRight {
block-size: calc(var(--total-height) - (var(--outer-thickness) * 2) * var(--m));
inline-size: calc(var(--outer-thickness) * var(--m));
}
.kallax__upper,
.kallax__lower,
.kallax__sideLeft,
.kallax__sideRight,
.kallax__back {
background-color: var(--kallax-color);
background-image: var(--kallax-texture);
box-shadow: inset 0 0 calc(20 * var(--m)) 0 oklch(0% 0 0deg / 10%);
position: absolute;
transform-style: preserve-3d;
}
.kallax__upper,
.kallax__lower {
block-size: calc(var(--total-depth) * var(--m));
inset-inline: 0;
}
.kallax__upper {
inset-block-end: 100%;
rotate: 1 0 0 90deg;
transform-origin: center bottom;
}
.kallax__lower {
inset-block-start: 100%;
rotate: 1 0 0 -90deg;
transform-origin: center top;
}
.kallax__sideLeft,
.kallax__sideRight {
inline-size: calc(var(--total-depth) * var(--m));
inset-block: 0;
}
.kallax__sideLeft {
inset-inline-end: 100%;
rotate: 0 1 0 -90deg;
transform-origin: right center;
}
.kallax__sideRight {
inset-inline-start: 100%;
rotate: 0 1 0 90deg;
transform-origin: left center;
}
.kallax__back {
inset: 0;
translate: 0 0 calc((var(--total-depth) * var(--m)) * -1);
}
.kallax__screws {
align-content: space-between;
display: grid;
grid-template-columns: repeat(2, calc(var(--screw-size) * var(--m)));
grid-template-rows: repeat(2, calc(var(--screw-size) * var(--m)));
inset: calc(var(--screw-size) * var(--m));
justify-content: space-between;
position: absolute;
}
.kallax__screw {
background-color: var(--c-screw);
border-radius: 50%;
block-size: calc(var(--screw-size) * var(--m));
inline-size: calc(var(--screw-size) * var(--m));
position: relative;
}
.kallax__screw::after {
background-color:
color-mix(
in oklch,
var(--c-screw),
oklch(0% 0 0deg)
);
clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
content: '';
inset: 30%;
position: absolute;
}
fieldset {
background-color: var(--c-ikea-blue);
border: 1px solid var(--c-ikea-yellow);
border-radius: 5px;
color: var(--c-ikea-yellow);
display: inline-block;
font-weight: bold;
margin-inline: auto;
padding: 10px 30px 20px;
position: relative; /* Bring it in front of Kallax! */
text-transform: uppercase;
}
legend {
background-color: var(--c-ikea-blue);
border: 1px solid var(--c-ikea-yellow);
border-radius: 5px;
padding: 2px 5px;
/* color: var(--c-ikea-blue); */
}
input {
accent-color: var(--c-ikea-yellow);
margin: 0;
}
label:not(:last-child) {
margin-inline-end: 10px;
}
const radios = document.querySelectorAll('input[type="radio"]');
const kallaxControl = document.querySelector('.kallax__control');
radios.forEach(radio => {
radio.addEventListener('change', (e) => {
kallaxControl.style.setProperty('--kallax-color', `var(--c-${e.target.value}`);
kallaxControl.style.setProperty('--kallax-texture', `var(--t-${e.target.value}`);
});
});
let isDragging = false;
let previousX = 0;
let previousY = 0;
let rotateX = -20;
let rotateY = 0;
let velocityX = 0;
let velocityY = 0;
let autoRotate = true;
function animate() {
if (autoRotate) {
rotateY += 0.1;
} else {
rotateX -= velocityY;
rotateY += velocityX;
// Apply friction.
velocityX *= 0.95;
velocityY *= 0.95;
// Stop completely if velocity is low.
if (Math.abs(velocityX) < 0.001 && Math.abs(velocityY) < 0.001) {
velocityX = 0;
velocityY = 0;
}
}
kallaxControl.style.transform = `rotateX(${rotateX}deg) rotateY(${rotateY}deg)`;
requestAnimationFrame(animate);
}
// Mouse events.
kallaxControl.addEventListener('mousedown', (e) => {
isDragging = true;
autoRotate = false;
previousX = e.clientX;
previousY = e.clientY;
});
window.addEventListener('mousemove', (e) => {
if (!isDragging) return;
const deltaX = e.clientX - previousX;
const deltaY = e.clientY - previousY;
velocityX = deltaX * 0.1;
velocityY = deltaY * 0.1;
rotateY += velocityX;
rotateX -= velocityY;
previousX = e.clientX;
previousY = e.clientY;
});
window.addEventListener('mouseup', () => {
isDragging = false;
autoRotate = true;
});
// Touch events.
kallaxControl.addEventListener('touchstart', (e) => {
isDragging = true;
autoRotate = false;
previousX = e.touches[0].clientX;
previousY = e.touches[0].clientY;
});
kallaxControl.addEventListener('touchmove', (e) => {
const deltaX = e.touches[0].clientX - previousX;
const deltaY = e.touches[0].clientY - previousY;
velocityX = deltaX * 0.1;
velocityY = deltaY * 0.1;
rotateY += velocityX;
rotateX -= velocityY;
previousX = e.touches[0].clientX;
previousY = e.touches[0].clientY;
});
kallaxControl.addEventListener('touchend', () => {
isDragging = false;
autoRotate = true;
});
// Start animation loop.
requestAnimationFrame(animate);
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.