Home > database >  Change div opacity when scrolling
Change div opacity when scrolling

Time:09-28

I would like to have div elements fade in and out when scrolling over them by changing the opacity. It sounds really simple but can't get it to work.

The problem I have is that the div are in the middle of my page and not on top, so scrollTop shouldn't work right?

var fade = $('.b_wrapper');
var range = 400;

$(window).on('scroll', function() {
  var st = $(this).scrollTop();
  fade.each(function() {
    var offset = $(this).offset().top;
    var height = $(this).outerHeight();
    offset = offset   height / 1;
    
    $(this).css({
      'opacity': 1 - (st   offset - range) / range
    });
  });
});
.content {
  height: 100px;
}

.b_wrapper {
  background: lightgreen;
  margin-top: 40px;
  padding: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<div ></div>
<div >
  <p>this is a div</p>
</div>
<div >
  <p>this is a div</p>
</div>
<div >
  <p>this is a div</p>
</div>
<div >
  <p>this is a div</p>
</div>
<div >
  <p>this is a div</p>
</div>
<div >
  <p>this is a div</p>
</div>
<div >
  <p>this is a div</p>
</div>

Little demo to hopefully make my question more clear: https://jsfiddle.net/gLnwy6h3/2/

CodePudding user response:

You can use the Intersection Observer API. It watches for changes in the intersection between a target element and its ancestor element or the viewport.

First, create a new observer with options:

let options = {
  root: null,
  threshold: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
}
let observer = new IntersectionObserver(callback, options);
  • root specifies either the ancestor (containing) element, e.g. with document.querySelector(), or the viewport with null.

  • threshold can take an array of intersection thresholds to watch for, which we'll directly use as opacity for our elements. So each time an element's intersection ratio with the viewport reaches one of these values, the callback is triggered. (You can use a function here to build the array if you want a more fine-grained sequence and don't want to write everything by hand.)

Next, add each element to the observer:

for (const target of document.querySelectorAll('.b_wrapper')) {
    observer.observe(target);
}

The callback is very simple, as we can directly use the provided intersectionRatio as opacity:

let callback = (entries, observer) => {
  entries.forEach((entry) => {
    entry.target.style.opacity = entry.intersectionRatio
  });
};

So much to get you started. Read the documentation, it's excellent and has many examples.

let callback = (entries, observer) => {
  entries.forEach((entry) => {
    entry.target.style.opacity = entry.intersectionRatio
  });
};

let options = {
  root: null,
  threshold: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
}
let observer = new IntersectionObserver(callback, options);

for (const target of document.querySelectorAll('.b_wrapper')) {
    observer.observe(target);
}
.b_wrapper{
  margin: 20px;
  padding: 20px;
  background: lightgreen;
}
<div ><p>this is a div</p></div>
<div ><p>this is a div</p></div>
<div ><p>this is a div</p></div>
<div ><p>this is a div</p></div>
<div ><p>this is a div</p></div>
<div ><p>this is a div</p></div>
<div ><p>this is a div</p></div>
<div ><p>this is a div</p></div>

CodePudding user response:

Probably not the best but here is my try :

  • On scroll, I check the position of every element to see wich one is the most centered

  • On window resize, I update the center of screen value

let centerOfScreen = window.innerHeight / 2;
let pageScroll;
let closestCenteredDivPosition = 999999;
let currentIndex;

let wrappers = document.getElementsByClassName("wrapper");
let positions = [];
for (let e of wrappers) {
  positions.push(e.offsetTop   e.offsetHeight / 2);
}

highlightMostCenteredDiv = () => {
  pageScroll = document.documentElement.scrollTop || document.body.scrollTop;
  let currentValue;
  for (let i = 0; i < positions.length; i  ) {
    currentValue = Math.abs(positions[i] - centerOfScreen - pageScroll);
    if (closestCenteredDivPosition > currentValue) {
      closestCenteredDivPosition = currentValue;
      currentIndex = i;
    }
  }
  if (!document.querySelector(".current")) {
    wrappers[currentIndex].classList.add("current");
  } else {
    if (wrappers[currentIndex] != document.querySelector(".current")) {
      document.querySelector(".current").classList.remove("current");
      wrappers[currentIndex].classList.add("current");
    }
  }
  closestCenteredDivPosition = 999999;
}

highlightMostCenteredDiv();

document.addEventListener("scroll", highlightMostCenteredDiv)

window.addEventListener("resize", () => {
  centerOfScreen = window.innerHeight / 2;
})
body {
  margin: 0;
}

.wrapper {
  background-color: orange;
  height: 100px;
  width: 100%;
  margin: 50px 0;
  opacity: 0.3;
  transition: opacity 1s ease;
}

.current {
  opacity: 1;
}
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>
<div ></div>

  • Related