Parallax with variable speeds

test showing 3 elements whose position changes at variable rates to the scroll value

by Richard Hunter

HTML

<div class="container">
  <div class="miz" data-parallax data-left="100" data-top="100">
  miz: constant rate
  </div>
  <div class="foo" data-parallax="0.5" data-left="150" data-top="100">
    foo: 1/2 rate
  </div>
  <div class="bar" data-parallax="2" data-left="200" data-top="100">
    bar: *2 rate
  </div>
  <div class="sentinel">

  </div>
</div>

CSS

body {
  overflow: hidden;
  height: 100%;
}

.container {
  height: 100vh;
  overflow-y: scroll;
  overflow-x: hidden;
  background: green;
  position: relative;
  perspective: 10px;
  perspective-origin: left top;
}

.sentinel {
  width: 1px;
  height: 1px;
  background: transparent;
  transform: translateY(2000px);
}

.foo,
.miz,
.bar {
  position: absolute;
  transform-origin: left top;
  width: 100px;
  height: 100px;
  left: 0;
  top: 0;
}

.foo {
  background: red;
}

.miz {
  background: lightblue;
}

.bar {
  background: yellow;
}

JavaScript

const PERSPECTIVE = 10;
const parallaxEls = document.querySelectorAll('[data-parallax]');

parallaxEls.forEach((el) => {
  const rate = el.dataset['parallax'] || 1;
  const {
    scale,
    distance
  } = getScaleAndDistance(rate);
  
  const left = el.dataset['left'];
  const top = el.dataset['top'];
  
  el.style.transform = `
  	translateX(${left * scale}px)
  	translateY(${top * scale}px) 
    translateZ(${distance}px) 
    scale(${scale})`;
});

function getScaleAndDistance(rate) {
  //   scale = (perspective - distance) / perspective
  //  perspective - distance = (scale * perspective)
  //  perspective - (scale * perspective) = distance
  //  distance = perspective - (scale * perspective)
  let scale = 1 / rate;
  let distance = PERSPECTIVE - (scale * PERSPECTIVE);

  return {
    scale,
    distance,
  };
}