user10953084
user10953084

Reputation:

How to add class on div scroll top and remove on div scroll out?

I am looking to add 'opacity' class to list items as the top of a div becomes visible in the viewport and remove the class once the div leaves the viewport and vice versa when scrolling up

Here is pen https://codepen.io/anon/pen/pYOrOV

I am not very familiar with jquery so might be making silly mistakes here but, Is it using the waypoint function the way to go or something more like the second option? any suggestions would be much appreciated thank you.

$('.wrapperright').scroll(function () {
    if(y >= s_body.top && y < e_body.top){
        $('#generationanxiety').addClass('opacity');
    }
    else 
    {
        $('#generationanxiety').removeClass('opacity');
    }
});

Upvotes: 2

Views: 3169

Answers (2)

Shikkediel
Shikkediel

Reputation: 5205

Checking if an item is in the viewport is easiest with getBoundingClientRect(). So I've used that in combination with data attributes on the div around the images - in order to match them with the id of the corresponding li item.

Demo with explanatory comments

$(window).on('load', function() {

  var pouch = $('.wrapperright'),
  items = pouch.find('div'),
  gate, spot = {},
  zone = pouch.scrollTop(),
  haze = 'opacity';

  $(this).resize(collectInfo).resize();

  pouch.scroll(function() {

    items.each(function() {

      var aim = $('#' + $(this).data('target')),
      edges = this.getBoundingClientRect(),
      apex = Math.round(edges.top),
      nadir = Math.round(edges.bottom);

      if (apex < gate && nadir > 0) aim.removeClass(haze);
      else aim.addClass(haze);
    });

    var rise = $('.bio li').not('.' + haze),
    turf = pouch.scrollTop();

    if (rise.length > 1) {
      if (turf > zone) rise.eq(0).addClass(haze);
      else rise.eq(1).addClass(haze);
    }

    zone = turf;
  });

  $('.bio li').click(function() {

    if (zone == spot[this.id]) return;

    pouch.stop().animate({scrollTop: spot[this.id]}, 1500);
  });

function collectInfo() {

  gate = $(this).height();

  items.each(function() {

    spot[$(this).data('target')] = Math.round($(this).position().top+zone);
  });
}
});

$(window).on('load', function() {

  var pouch = $('.wrapperright'),
  items = pouch.find('div'),
  gate, spot = {},
  zone = pouch.scrollTop(),
  haze = 'opacity';

  $(this).resize(collectInfo).resize();

  pouch.scroll(function() {

    items.each(function() {

      var aim = $('#' + $(this).data('target')),
      edges = this.getBoundingClientRect(),
      apex = Math.round(edges.top),
      nadir = Math.round(edges.bottom);

      if (apex < gate && nadir > 0) aim.removeClass(haze);
      else aim.addClass(haze);
    });

    var rise = $('.bio li').not('.' + haze),
    turf = pouch.scrollTop();

    if (rise.length > 1) {
      if (turf > zone) rise.eq(0).addClass(haze);
      else rise.eq(1).addClass(haze);
    }

    zone = turf;
  });

  $('.bio li').click(function() {

    if (zone == spot[this.id]) return;

    pouch.stop().animate({scrollTop: spot[this.id]}, 1500);
  });

function collectInfo() {

  gate = $(this).height();

  items.each(function() {

    spot[$(this).data('target')] = Math.round($(this).position().top+zone);
  });
}
});
html, body {
  margin: 0;
  overflow-x: hidden;
  overflow-y: hidden;
}

.wrapper {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  height: 100vh;
  margin: 0;
  grid-gap: 0;
}

.wrapperleft {
  grid-column-start: 1;
  grid-column-end: 1;
  grid-template-rows: auto;
  width: 50vw;
  max-height: 100%;
  overflow: hidden;
  margin: 0;
}

.bio {
  margin: 20px;
}

.bio ul {
  margin-top: 20px;
  padding: 0;
}

.bio h1 {
  font-family: sans-serif;
  font-weight: 400;
  font-size: 3.2em;
  list-style: none;
  margin: 0;
  border-bottom: 2px solid #000;
  display: inline;
}

.bio ul li {
  font-family: sans-serif;
  font-weight: 400;
  font-size: 3.2em;
  list-style: none;
  padding-bottom: 10px;
  cursor: pointer;
  -webkit-transition: all 0.3s ease;
  transition: all 0.3s ease;
}

.back {
  position: absolute;
  bottom: 0;
  margin-left: 20px;
}

.back h1 {
  font-family: sans-serif;
  font-weight: 400;
  font-size: 1.5em;
}

.wrapperright {
  grid-column-start: 2;
  grid-column-end: 2;
  grid-template-rows: 200px;
  border-left: 2px solid #000;
  width: 50vw;
  overflow-x: hidden;
  overflow-y: auto;
}

.wrapperright img {
  width: 50vw;
  max-height: 100%;
  display: block;
}

.opacity {
  opacity: 0.4;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="wrapper">
  <div class="wrapperleft">
    <div class="bio">
      <ul>
       <li id="generation" class="opacity">01 Generation Anxiety</li>
       <li id="lekhena" class="opacity">02 Lekhenaporter.com</li>
       <li id="bodys" class="opacity">03 Body(s) Under Negotiation</li>
       <li id="glitter" class="opacity">04 Glitter Boy Cosmetics</li>
       <li id="juice" class="opacity">05 Juice WRLD Cover Art</li>
      </ul>
    </div>
    <div class="back">
      <h1>← Back</h1>
    </div>
  </div>
  <div class="wrapperright">
    <img src="http://media-s3-us-east-1.ceros.com/vevo/images/2017/11/07/8d018e81643b41c3561b5ab4f5bf504b/iamddb-contact-sheet1.jpg" alt="image1">
    <div data-target="generation">
      <img src="https://dazedimg-dazedgroup.netdna-ssl.com/786/azure/dazed-prod/1180/0/1180791.jpg" alt="image2">
    </div>
    <div data-target="lekhena">
      <img src="http://kendrickbrinson.com/wp-content/uploads/2014/03/YoungThug_Portraits-029.jpg" alt="image3">
    </div>
    <div data-target="bodys">
      <img src="https://www.thunderstudios.com/wp-content/uploads/2016/03/Calvin-15.jpg" alt="image4">
    </div>
    <div data-target="glitter">
      <img src="https://4c79id2ej5i11apui01ll2wc-wpengine.netdna-ssl.com/wp-content/uploads/2018/01/IAMDDB-Gallery-3.jpg" alt="image5">
    </div>
    <div data-target="juice">
      <img src="https://www.thunderstudios.com/wp-content/uploads/2016/03/Calvin-15.jpg" alt="image6">
    </div>
  </div>
</div>

The same relationship between id of the list item and matching data attribute I've also used to store the scrolling positions of the images ahead of clicking, in order to fix the anchor scrolling part.

After some feedback an extra bit of code was added to make sure only one list item gets highlighted at a time, depending on which image is "emerging" (by checking the scroll direction).

I've somewhat changed the HTML also because div isn't a valid child of ul and the wrapper element seems otherwise unnecessary here anyway. Lastly a minor CSS fix to correct the overflow of the element on the right and a few band aids to fix horizontal overflow issues (vw isn't very universally compatible with desktop browsers). The style is a bit out of the scope of the question otherwise, I've altered it only minimally.

Upvotes: 1

Tim Gottgetreu
Tim Gottgetreu

Reputation: 495

Maybe this...

 var topofDiv = $("#generationanxiety").offset().top; //gets offset div
 var height = $("#generationanxiety").outerHeight(); //gets height of div

 $(window).scroll(function(){
     if($(window).scrollTop() > (topofDiv + height)){
       console.log('This is where the div bottom leaves the window.')
       $('#generationanxiety').removeClass('opacity');
       }
      else{
       $('#generationanxiety').addClass('opacity');
      }
});

and for smoothness add this additional CSS Code:

#WrapperDiv{
     -webkit-transition: all 0.5s ease;
     -moz-transition: all 0.5s ease;
     -o-transition: all 0.5s ease;
     transition: all 0.5s ease;
 }

to the parent div

Upvotes: 0

Related Questions