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,
};
}