parallax scroll

Image moves according to scroll

by uto usui

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js"></script>
<div class="wrap">
  <div class="box">
    <div class="inner"></div>
  </div>
  <div class="box">
    <div class="inner"></div>
  </div>
  <div class="box">
    <div class="inner"></div>
  </div>
  <div class="box">
    <div class="inner"></div>
  </div>
  <div class="box">
    <div class="inner"></div>
  </div>
  <div class="box">
    <div class="inner"></div>
  </div>
  <div class="box">
    <div class="inner"></div>
  </div>
</div>

SCSS

* {
  line-height: 1;
  box-sizing: border-box;
}

.wrap {
  text-align: center;
}

.box {
  width: 300px;
  height: 300px;
  overflow: hidden;
  border: 5px solid rgba(black, .5);
  transition: all .5s;
  //
  + .box {
    margin-top: 150px;
  }
  opacity: 0;
  //
  &.is-show {
    opacity: 1;
  }
}

.inner {
  width: 400px;
  height: 400px;
  padding: 1rem;
  background-color: lightblue;
  background-position: center center;
  background-size: cover;
  background-image: url(https://source.unsplash.com/random/1000x1000);
}

JavaScript

const anim = (target, value) => {

  TweenMax.to(target, ".5", {

    y: value,

  });

};


class scrollPosition {

  constructor(targets, callbackIn) {

    this.targets = [...document.querySelectorAll(targets)];
    this.windowH = window.innerHeight;
    this.scrollY = 0;
    this.offsetTop = [];
    this.height = [];
    this.show = [];
    this.value = [];
    this.offset = 100;

    this.callbackIn = typeof callbackIn === 'function' ? callbackIn : () => {};

    this.getItem();
    this.init();

    return this;

  }


  init() {

    window.addEventListener('scroll', () => {

      this.scrollY = window.pageYOffset;
      this.check();

    });

    this.check();

  }

  getItem() {

    this.targets.forEach((el, i) => {

      let rect = el.getBoundingClientRect();

      this.offsetTop[i] = rect.top;
      this.height[i] = el.offsetHeight;

    });

  }

  check() {

    this.targets.forEach((el, i) => {

      this.show[i] = (this.scrollY + this.windowH > this.offsetTop[i] + this.offset) && (this.scrollY < this.offsetTop[i] - this.offset + this.height[i]);
      this.value[i] = this.scrollY + this.windowH - this.offsetTop[i] - this.offset;

      if (this.show[i]) {

        el.classList.add('is-show');
        this.callbackIn.call(this, el, i);

      } else {

        el.classList.remove('is-show');

      }

    });

  }

}

const box = new scrollPosition('.box', function(el, i) {

  let amount = 100;
  let value = this.value[i] / this.windowH * amount * -1;

  if (this.show[i]) {

    anim(el.querySelector('.inner'), value);

  }

});