<div class="container">
  <div id="top">
    <a href="#bottom">To Bottom</a>
  </div>
  <div class="box"></div>
  <div id="bottom">
    <a href="#top">To Top</a>
  </div>
</div>
html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  font: 16px 'Segoe UI', Arial, Helvetica, sans-serif;
}

.container {
  position: relative;
  width: 100%;
  height: 400vh;
}

.box {
  position: fixed;
  top: calc(50% - 100px);
  left: 0;
  width: 200px;
  height: 200px;
  background: tomato;
  transform: translateX(calc(1px * var(--offset)));
}

#top,
#bottom {
  position: absolute;
  left: 0;
  right: 0;
  padding: 10px;
  text-align: center;
}

#top {
  top: 0;
}

#bottom {
  bottom: 0;
}
const box = document.querySelector('.box');
let rect = document.body.getBoundingClientRect();

const normalize = (min, max, value) => {
  return (value - min) / (max - min);
};

const lerp = (min, max, value) => {
  return (1 - value) * min + value * max;
};

const map = (minSource, maxSource, minTarget, maxTarget, value) => {
  return lerp(minTarget, maxTarget, normalize(minSource, maxSource, value));
};

const update = () => {
  box.style.setProperty('--offset', map(0, rect.height - innerHeight, 0, rect.width - 200, scrollY));
};

window.addEventListener('scroll', update);

window.addEventListener('resize', () => {
  rect = document.body.getBoundingClientRect();
  update();
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.