4

Currently, my background div text changes based on which element is on screen.

Is there a way to make it so:

  • the text fades out as the user scrolls
  • then fades in and is at 100% when the div is in the center of screen
  • then fades out as user scrolls further
  • does the opposite when the user scrolls back up

I have seen solutions based on JQuery but I want to get this done with vanilla javascript.

const section = document.querySelectorAll('.check');
const bg = document.querySelector('.bg');

const observer = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    className = entry.target.classList[1];
    console.log(className);
    if (entry.isIntersecting) {
      if (className === 'first') {
        bg.innerHTML = 'FIRST';
      } else if (className === 'second') {
        bg.innerHTML = 'SECOND';
      } else if (className === 'third') {
        bg.innerHTML = 'THIRD';
      } else if (className === 'fourth') {
        bg.innerHTML = 'FOURTH';
      } else if (className === 'fifth') {
        bg.innerHTML = 'FIFTH';
      } else if (className === 'sixth') {
        bg.innerHTML = 'SIXTH';
      }
    } else {
    }
  })
});

section.forEach(section => {
  observer.observe(section);
});
.check {
  width: 100px;
  height: 20px;
  background-color: red;
  color: white;
  padding: 20px;
}

.spacer {
  height: 100vh;
  width: 100px;
}

.bg {
  position: fixed;
  font-size: 100px;
  color: #c9c9c9;
  z-index: -100;
}

.fadeIn {
  opacity: 1;
}

.fadeOut {
  opacity: 0;
}
<div class="bg">
  BG
</div>

<div class="check first">
FIRST
</div>
<div class="spacer">
</div>

<div class="check second">
SECOND
</div>
<div class="spacer">
</div>

<div class="check third">
THIRD
</div>
<div class="spacer">
</div>

<div class="check fourth">
FOURTH
</div>
<div class="spacer">
</div>

<div class="check fifth">
FIFTH
</div>
<div class="spacer">
</div>

<div class="check sixth">
SIXTH
</div>
<div class="spacer">
</div>
amars
  • 407
  • 6
  • 15

1 Answers1

1

Not my finest work but kind of works

const section = document.querySelectorAll('.check');
const bgText = document.querySelector('.bg__text');

const capitalize = (value) => {
  const [firstChar, ...rest] = value;

  return firstChar.toUpperCase() + rest.join('').toLowerCase()
}



const checkpoints = Array.from(document.querySelectorAll(".check"))
  .map(element => ({
    id: element.classList[1],
    element,
    rect: element.getBoundingClientRect()
  }));

let currentElement = null;

window.addEventListener("scroll", () => {
  const scrollY = window.scrollY;
  const innerHeight= window.innerHeight;
  
  const distances = checkpoints.map(pr => ({
    ...pr,
    distance: Math.abs(pr.rect.y - scrollY)
  }));
  
  distances.sort((prev, next) => prev.distance > next.distance ? 1 : -1);
  
  const distance = distances.find(pr => pr.element === currentElement).distance;
  
  let opacity = distance / innerHeight;
  opacity = opacity > 0.5 ? 1 - opacity : opacity;
  bgText.style.opacity = opacity * 2;
  
})

const observer = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    const element = entry.target;
    className = element.classList[1];

    if (!entry.isIntersecting) {
      return;
    }

    currentElement = element;
    bgText.textContent = capitalize(className);

  })
});

section.forEach(section => {
  observer.observe(section);
});
.check {
  width: 100px;
  height: 20px;
  background-color: red;
  color: white;
  padding: 20px;
}

.spacer {
  height: 100vh;
  width: 100px;
}

.bg {
  position: fixed;
  font-size: 100px;
  color: #c9c9c9;
  z-index: -100;
}

.fadeIn {
  opacity: 1;
}

.fadeOut {
  opacity: 0;
}
<div class="bg">
  <div class="bg__text"></div>
</div>

<div class="check first">
  FIRST
</div>
<div class="spacer">
</div>

<div class="check second">
  SECOND
</div>
<div class="spacer">
</div>

<div class="check third">
  THIRD
</div>
<div class="spacer">
</div>

<div class="check fourth">
  FOURTH
</div>
<div class="spacer">
</div>

<div class="check fifth">
  FIFTH
</div>
<div class="spacer">
</div>

<div class="check sixth">
  SIXTH
</div>
<div class="spacer">
</div>
Józef Podlecki
  • 10,453
  • 5
  • 24
  • 50