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);
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.